Welcome to MSDN Blogs Sign in | Join | Help

The blog is close down

We will no longer keep this blog.

For information about WPF, you can find more in Kevin Moore's blog: http://blogs.msdn.com/okoboji/ 

Thanks,

ATC Avalon Team

 

A Fancy StatusBar

Download and try it! 

When moving Mouse over an item, the item jumps up until Mouse leaves. The key steps to achieve it are as follows. 

1.      Subclass StatusBarItem and add new property ImagePath. Therefore, we can pass image to StatusBarItem easily.

 

2.      Subclass StatusBar and override MouseLeave and MouseMove event. In MouseMove event handler, find current item according to mouse position, and then change each item’s position by changing Canvas.Top property. When Mouse Leave, restore each item to original position.

Declaimer: This posting is provided "AS IS" with no warranties, and confers no rights.

Posted by ATC Avalon Team | (Comments Off)
Filed under:

Attachment(s): StatusBarExtension.zip

How to Create a Custom View

One of the most powerful features of ListView is supporting custom views. If built-in views do not apply your scenarios, you can easily write your own. ListView will handle your views the same way with built-in views.

Creating a custom view is pretty simple. ListView control has done quiet a bit of work to make the implementation easy. Here are main steps to follow. Firstly, a class should be created and it should derive from ViewBase directly or indirectly. Then define the style of the view in a resource file. Finally link them together using ComponentResourceKey. In this blog I will show you how to create a custom view named ImageView. ImageView is used to display thumbnail of image files. The snapshot is listed below.

 Step 1. Define ImageView class

All you have to do is to subclass ViewBase.

public class ImageView : ViewBase

{

}

 Step 2. Define Style for ImageView

Two styles should be defined in a resource file. One is for ListView and the other is for ListViewItem. If you only want to do a little modification on the original one, you can use the following code. It will merge your style into its original style. The magic lies in the keyword “BasedOn”. It means your style definition is based on another style definition.

<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListBox}}">

NOTE: if you forget to define Template in styles, ListView will show nothing.

The following XAML code is digested from the style definitions for ImageView.

<Style TargetType="{x:Type ListView}" BasedOn="{StaticResource {x:Type ListBox}}">

  <Setter Property="BorderBrush" Value="Black"/>

  <Setter Property="BorderThickness" Value="0.5"/>

  <Setter Property="Template">

    <Setter.Value>

      <ControlTemplate>

        <Border Name="bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"

                Background="{TemplateBinding Background}" Margin="{TemplateBinding Margin}">

          <ScrollViewer Margin="{TemplateBinding Padding}">

            <WrapPanel ItemWidth="150" IsItemsHost="True" MinWidth="100"

                       Width="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}">

            </WrapPanel>

          </ScrollViewer>

        </Border>

      </ControlTemplate>

    </Setter.Value>

  </Setter>

</Style>

 

<Style TargetType='{x:Type ListViewItem}' BasedOn='{StaticResource {x:Type ListBoxItem}}'>

  <Setter Property='Padding' Value='3'/>

  <Setter Property='Margin' Value='5'/>

  <Setter Property='HorizontalContentAlignment' Value='Center'/>

   <Setter Property="ContentTemplate">

    <Setter.Value>

      <DataTemplate>

        <Border Background="White">

          <Image Margin="3" Source="{Binding FullName}"/>

        </Border>

      </DataTemplate>

    </Setter.Value>

  </Setter>

</Style>

 

Step 3. Link them together

The link method here is using ComponentResourceKey. Firstly give a key to each style defined before.

<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type l:ImageView},ResourceId=ImageView}">

</Style>

 

<Style x:Key="{ComponentResourceKey TypeInTargetAssembly={x:Type l:ImageView},ResourceId=ImageViewItem}"}">

</Style>

Then set DefaltStyleKey and ItemContainerStyleKey in ImageView class.

public class ImageView : ViewBase

{

    protected override object DefaultStyleKey

    {

        get { return new ComponentResourceKey(GetType(), "ImageView"); }

    }

 

 

    protected override object ItemContainerDefaultStyleKey

    {

        get { return new ComponentResourceKey(GetType(), "ImageViewItem"); }

    }

 

}

 

Step 4. Use it in ListView

It is used like GridView.

<ListView>

  <ListView.View>

    <l:ImageView />

  </ListView.View>

</ListView>

 We’re done!

Posted by ATC Avalon Team | 8 Comments

Attachment(s): CustomView.zip

How to display data from database?

It is common for ListView to display data from database. In this blog, I will briefly introduce how to do this. To achieve this, we need to resolve two problems:

  1. Binding data table to ListView;
  2. Binding fields of data table to GridViewColumns.

Binding data table to ListView

How to bind data of a DataTable to ListView depend on how to use DataTable, but the basic rules are the same:

 

1.      If use DataTable directly, first set the DataTable to the ListView.DataContext. And then bind ListView.ItemsSource to ListView.DataContext. The following code is a simple sample:

string connString = "CONNECTION STRING";

SqlConnection conn = new SqlConnection(connString);

SqlDataAdapter adapter = new SqlDataAdapter();

adapter.SelectCommand = new SqlCommand("COMMAND", conn);

DataSet _dataSet = new DataSet();

adapter.Fill(_dataSet, "DATATABLE NAME");

DataTable table = _dataSet.Tables["DATATABLE NAME"];

Binding bind = new Binding();

listView.DataContext = table;

listView.SetBinding(ListView.ItemsSourceProperty, bind);

 

2.      If define wrapper classes for DataTable, wrapper classes should implement IEnumerable, so that instances of the wrapper classes can be directly assigned to ListView.ItemsSource. Fortunately, the Data Source Manger in Visual Studio 2005 can automatically create wrapper classes if you use it to manage your data source in your application.

3.      In some cases, you may need to dynamically add data rows into the source. For example, start a background thread to insert items into the data source. In this case, you can use ObservableCollection directly or create a wrapper class implementing INotifyCollectionChanged interface.

 

Binding fields of data table to GridViewColumns

  1. When defining data source for ListView in the first way mentioned above, use data field names in the DisplayMemberBinding directly, for example:

<GridViewColumn DisplayMemberBinding=”{Binding FIELDNAME}”/>

 

  1. If use wrapper class for data rows, just use property names in the wrapper class.

 In fact, it is straightforward to display DataTable with ListView. Two bindings are keys: one for ItemsSource of ListView and the other for fields in a row.

 

Declaimer: This posting is provided "AS IS" with no warranties, and confers no rights.

Posted by ATC Avalon Team | 1 Comments
Filed under:

Fixed-Width Column in ListView: A Column that cannot be resized

A fixed-width column is a column that cannot be resized by mouse dragging or double-clicks. You can find instances in outlook. Currently two methods can be used to achieve the effect. One is to restyle GridViewColumnHeader to remove the gripper inside its Template. The other is to subclass GridViewColumn to restrict columns' width to a fixed size. Today's topic is about the second solution. The resulting column is a little bit different from the restyling one because there is still a gripper inside GridViewColumnHeader. When mouse is over the gap between columns, the cursor is still changed to the resizing cursor.

The main WPF elements we are going to cover in this session are GridViewColumn, dependency property definition, dependency property coercion.

 Step 1. Subclass GridViewColumn

The key in this step is to override WidthProperty's metadata to make it call CoerceWidth() to coerce its value when a new value is available.

public class FixedWidthColumn : GridViewColumn {

    static FixedWidthColumn() {

        WidthProperty.OverrideMetadata(typeof(FixedWidthColumn),

            new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceWidth)));

}

 

private static object OnCoerceWidth(DependencyObject o, object baseValue) {

        return baseValue;

    }

}

 Step 2. Add a dependency property FixedWidth

The FixedWidth is used to set column's fixed width in spite of whatever the column's width is. The keys in this step are:

1.      Define a dependency property.

2.      When FixedWidth is changed, it calls CoerceValue() to coerce Width into the new value.

public double FixedWidth {

    get { return (double)GetValue(FixedWidthProperty); }

    set { SetValue(FixedWidthProperty, value); }

}

 

public static readonly DependencyProperty FixedWidthProperty =

    DependencyProperty.Register(

        "FixedWidth",

        typeof(double),          

        typeof(FixedWidthColumn),

        new FrameworkPropertyMetadata(double.NaN, new PropertyChangedCallback(OnFixedWidthChanged)));

 

private static void OnFixedWidthChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) {

    FixedWidthColumn fwc = o as FixedWidthColumn;

    if (fwc != null)

        fwc.CoerceValue(WidthProperty);

}

Step 3. Rewrite CoerceWidth() to make it always return FixedWidth

Then the Width will always get the same value whatever value is set on Width.

private static object OnCoerceWidth(DependencyObject o, object baseValue) {

    FixedWidthColumn fwc = o as FixedWidthColumn;

    if (fwc != null)

        return fwc.FixedWidth;

    return baseValue;

}

Step 4. Use it in GridView

It is used like normal GridViewColumn.

<GridView xmlns:l="clr-namespace:FixedWidthColumnSample">

  <l:FixedWidthColumn Header="Coerce Fixed-Width Column"

                      DisplayMemberBinding="{Binding Name}"

                      FixedWidth="100"/>

</GridView>

 

 We're done!

 

This sample is based on the February CTP.

 

Declaimer: This posting is provided "AS IS" with no warranties, and confers no rights.

Other solutions to implement Alternate Background

We have found three solutions to achieve alternative background scenarios so far. The first one is provided in the previous post. Now we will describe another two.

 

The second solution:

 Derive from ListView, override PrepareContainerForItemOverride method and return the container with the correct background. And in your xaml file, replace ListView with SubListView. When items change, call ListView.Items.Refresh method.

 

The code is as follows.

public class SubListView : ListView

    {

        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

        {

            base.PrepareContainerForItemOverride(element, item);

            if (View is GridView)

            {

                int index = ItemContainerGenerator.IndexFromContainer(element);

                ListViewItem lvi = element as ListViewItem;

                if (index % 2 == 0)

                {

                    lvi.Background = Brushes.LightBlue;

                }

                else

                {

                    lvi.Background = Brushes.LawnGreen;

                }

            }

        }

    }

 

 

The third solution:

Creat a StyleSelector for ListView.ItemContainerStyleSelector property, in which alternate styles. Reset the containerStyleSeletor property when collection changes.

 

The code is as follows.

public class ListViewItemStyleSelector : StyleSelector

    {

        public override Style SelectStyle(object item, DependencyObject container)

        {