Click here to Skip to main content
15,917,565 members
Home / Discussions / WPF
   

WPF

 
AnswerRe: Bind ObservableCollection to a Grid Pin
Mark Salsbery12-Nov-08 12:22
Mark Salsbery12-Nov-08 12:22 
GeneralRe: Bind ObservableCollection to a Grid Pin
ezazazel12-Nov-08 20:02
ezazazel12-Nov-08 20:02 
GeneralRe: Bind ObservableCollection to a Grid Pin
Mark Salsbery12-Nov-08 20:37
Mark Salsbery12-Nov-08 20:37 
GeneralRe: Bind ObservableCollection to a Grid Pin
ezazazel13-Nov-08 2:13
ezazazel13-Nov-08 2:13 
GeneralRe: Bind ObservableCollection to a Grid Pin
Gideon Engelberth13-Nov-08 8:16
Gideon Engelberth13-Nov-08 8:16 
GeneralRe: Bind ObservableCollection to a Grid Pin
ezazazel13-Nov-08 9:55
ezazazel13-Nov-08 9:55 
GeneralRe: Bind ObservableCollection to a Grid Pin
Gideon Engelberth13-Nov-08 12:47
Gideon Engelberth13-Nov-08 12:47 
GeneralRe: Bind ObservableCollection to a Grid [modified] Pin
Mark Salsbery14-Nov-08 12:40
Mark Salsbery14-Nov-08 12:40 
I personally really don't like the idea of having UI elements in the collection
when WPF provides data templating to build the UI for you so you can keep your
UI and data separate.

Given that, your requirements, and the fact that I've never tried making
a custom ItemsControl before, I thought I'd play around with this.
Always fun to learn new stuff!

Here's what I came up with...

ezazazel wrote:
Rule1: PositionX and PositionY inside the softwarematrix are taken out of the properties from the class
Rule2: BackgroundColor is defined by the status of an enumeration


Given these rules, I started by creating an "Obs" class, based on the name of your
originally posted "ObsCls" class. This class holds a text string, the row and column
where it should be in the grid, and a status enumeration.

So you can change an Obs objects properties and have the change magically appear in the UI,
I used INotifyPropertyChanged (dependency properties would work fine too).

I also added a class called "ObsList", which is an ObservableCollection of Obs objects.

Here's that:
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Data;
using System.Windows.Controls;
using System.ComponentModel;


namespace MyNamespace
{
    public class Obs : INotifyPropertyChanged
    {
        public enum ObsStatus
        {
            Off,
            On
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private string _name;
        public string Name
        {
            get
            {
                return _name;
            }
            set
            {
                _name = value;
                OnPropertyChanged("Name");
            }
        }

        private int _row;
        public int Row
        {
            get
            {
                return _row;
            }
            set
            {
                _row = value;
                OnPropertyChanged("Row");
            }
        }


        private int _col;
        public int Col
        {
            get
            {
                return _col;
            }
            set
            {
                _col = value;
                OnPropertyChanged("Col");
            }
        }


        private ObsStatus _status;
        public ObsStatus Status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
                OnPropertyChanged("Status");
            }
        }

        public Obs(string str, int row, int col)
        {
            Name = str;
            Row = row;
            Col = col;
            Status = ObsStatus.Off;
        }

        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

    public class ObsList : ObservableCollection<Obs>
    {
    }
}

I also created a class derived from ObsList to use as static data in the designer:
public class ObsCls_designer : ObsList
{
    public ObsCls_designer()
    {
        Obs newobs = new Obs("1", 0, 0);
        newobs.Status = Obs.ObsStatus.Off;
        Add(newobs);

        newobs = new Obs("2", 1, 1);
        newobs.Status = Obs.ObsStatus.On;
        Add(newobs);

        newobs = new Obs("3", 2, 2);
        newobs.Status = Obs.ObsStatus.Off;
        Add(newobs);

        newobs = new Obs("4", 3, 3);
        newobs.Status = Obs.ObsStatus.On;
        Add(newobs);

        newobs = new Obs("5", 4, 4);
        newobs.Status = Obs.ObsStatus.Off;
        Add(newobs);

    }
}

That's it on the data side.

For the UI, you need an ItemsControl or derived to bind a collection of data to.
Since none of the built-in ItemsControls use a Grid as an ItemsPanel, I needed
to make my own custom ItemsControl. Here's the XAML in its entirety, wrapped in
a Window to test it all:
<Window x:Class="MyNamespace.TestItemsControlGridWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyNamespace" 
    Title="TestWindow" Height="204" Width="293" ShowInTaskbar="False" WindowStartupLocation="CenterOwner" >
    <Window.Resources>
        <local:ObsCls_designer x:Key="obsCls_designer" />
        <local:ObsItemStyleSelector x:Key="obsItemStyleSelector"/>
    </Window.Resources>
    <StackPanel Width="Auto" Height="Auto">
        <Border Width="Auto" Height="Auto" BorderThickness="1,1,1,1" BorderBrush="#FF505050" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="4,4,4,4">
            <Grid Width="Auto" Height="Auto" HorizontalAlignment="Center" VerticalAlignment="Center">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition />
                </Grid.ColumnDefinitions>
                <ItemsControl Loaded="ItemsControl_Loaded" ItemContainerStyleSelector="{StaticResource obsItemStyleSelector}" ItemsSource="{Binding Source={StaticResource obsCls_designer}}" Width="Auto" Height="Auto" >
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Grid ShowGridLines="True">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" MinHeight="25"/>
                                    <RowDefinition Height="Auto" MinHeight="25"/>
                                    <RowDefinition Height="Auto" MinHeight="25"/>
                                    <RowDefinition Height="Auto" MinHeight="25"/>
                                    <RowDefinition Height="Auto" MinHeight="25"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                                    <ColumnDefinition Width="Auto" MinWidth="50"/>
                                </Grid.ColumnDefinitions>
                            </Grid>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate DataType="{x:Type local:Obs}">
                            <Button Click="Button_Click">
                                <Button.Style>
                                    <Style TargetType="{x:Type Button}" >
                                        <Setter Property="Content" Value="{Binding Path=Name}"/>
                                        <Setter Property="Width" Value="50"/>
                                        <Setter Property="Height" Value="Auto"/>
                                        <Setter Property="Margin" Value="2"/>
                                        <Setter Property="Background" Value="#80BBBB00"/>
                                        <Setter Property="Foreground" Value="#FF000000"/>
                                        <Style.Triggers>
                                            <DataTrigger Binding="{Binding Path=Status}" Value="On">
                                                <Setter Property="Background" Value="#80FFFF00"/>
                                                <Setter Property="Foreground" Value="#FFFF0000"/>
                                            </DataTrigger>
                                        </Style.Triggers>
                                    </Style>
                                </Button.Style>
                            </Button>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>
        </Border>
        <Button Content="Test" HorizontalAlignment="Center" VerticalAlignment="Center" Click="TestButton_Click"/>
    </StackPanel>
</Window>

For simplicity, I inlined all the style and template stuff.

The ItemsControl.ItemTemplate is the key. It determines how items will
appear in the ItemsControl. I used a DataTemplate bound to the Obs type
which contains just a Button.

Here's the code for the ObsItemStyleSelector (thanks Gideon!) used to
bind the Obs.Row/Obs.Col properties to the Grid.Row/Grid.Column attached
properties:
public class ObsItemStyleSelector : StyleSelector
{
    public override Style SelectStyle(object item, DependencyObject container)
    {
        Obs obs = item as Obs;
        ContentPresenter cp = container as ContentPresenter;

        if (null != obs && null != cp)
        {
            Binding binding = new Binding("Row");
            binding.Source = obs;
            cp.SetBinding(Grid.RowProperty, binding);

            binding = new Binding("Col");
            binding.Source = obs;
            cp.SetBinding(Grid.ColumnProperty, binding);
        }

        return null;
    }
}

To tie it all together and try it out, here's the code-behind for the test window:
public partial class TestItemsControlGridWindow : Window
{
    private ObsList obslist = new ObsList();

    public TestItemsControlGridWindow()
    {
        InitializeComponent();
    }

    private void ItemsControl_Loaded(object sender, RoutedEventArgs e)
    {
        ItemsControl itemscontrol = sender as ItemsControl;

        itemscontrol.ItemsSource = obslist;

        Obs newobs = new Obs("1", 0, 0);
        newobs.Status = Obs.ObsStatus.Off;
        obslist.Add(newobs);

        newobs = new Obs("2", 1, 1);
        newobs.Status = Obs.ObsStatus.On;
        obslist.Add(newobs);

        newobs = new Obs("3", 2, 2);
        newobs.Status = Obs.ObsStatus.Off;
        obslist.Add(newobs);

        newobs = new Obs("4", 3, 3);
        newobs.Status = Obs.ObsStatus.On;
        obslist.Add(newobs);

        newobs = new Obs("5", 4, 4);
        newobs.Status = Obs.ObsStatus.Off;
        obslist.Add(newobs);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        Button button = sender as Button;
        Obs obs = button.DataContext as Obs;
        if (obs.Status == Obs.ObsStatus.Off)
            obs.Status = Obs.ObsStatus.On;
        else
            obs.Status = Obs.ObsStatus.Off;
    }

    private void TestButton_Click(object sender, RoutedEventArgs e)
    {
        // Test moving an object to another cell
        obslist[2].Col = 0;

        // Test adding a new object at runtime
        Obs newobs = new Obs("6", 0, 3);
        newobs.Status = Obs.ObsStatus.Off;
        obslist.Add(newobs);
    }
}

ItemsControl_Loaded() sets the ItemControl's ItemsSource to a fresh empty ObsList
Instead of using the designer data.
Button_Click() toggles the Obs object State On or Off to test the associated UI tigger.
TestButton_Click() tests moving an item and adding an item, both by just chaging the
objects properties!

Mark Salsbery
Microsoft MVP - Visual C++

Java | [Coffee]

modified on Saturday, November 15, 2008 1:02 PM

GeneralRe: Bind ObservableCollection to a Grid Pin
ezazazel15-Nov-08 1:54
ezazazel15-Nov-08 1:54 
GeneralRe: Bind ObservableCollection to a Grid Pin
Mark Salsbery15-Nov-08 6:46
Mark Salsbery15-Nov-08 6:46 
GeneralRe: Bind ObservableCollection to a Grid Pin
Mark Salsbery15-Nov-08 7:15
Mark Salsbery15-Nov-08 7:15 
QuestionComboBox's SelectedValue set to null when changing templates Pin
James J. Foster12-Nov-08 4:56
James J. Foster12-Nov-08 4:56 
QuestionAdobe Illustrator exporter to XAML Pin
DaveX8611-Nov-08 16:50
DaveX8611-Nov-08 16:50 
Questionhow can i read files from my silverlight 2 web folder Pin
ahmedhassan9611-Nov-08 12:41
ahmedhassan9611-Nov-08 12:41 
AnswerRe: how can i read files from my silverlight 2 web folder Pin
lneir12-Nov-08 18:42
lneir12-Nov-08 18:42 
QuestionWPF-Callable Folder Browser Source Code [modified] Pin
Mark Salsbery11-Nov-08 11:40
Mark Salsbery11-Nov-08 11:40 
AnswerRe: WPF-Callable Folder Browser Source Code Pin
Pete O'Hanlon11-Nov-08 11:44
mvePete O'Hanlon11-Nov-08 11:44 
GeneralRe: WPF-Callable Folder Browser Source Code Pin
Mark Salsbery11-Nov-08 11:55
Mark Salsbery11-Nov-08 11:55 
AnswerRe: WPF-Callable Folder Browser Source Code Pin
Jammer12-Nov-08 0:52
Jammer12-Nov-08 0:52 
GeneralRe: WPF-Callable Folder Browser Source Code Pin
Mark Salsbery12-Nov-08 8:41
Mark Salsbery12-Nov-08 8:41 
QuestionAdding events to objects in application.resources Pin
Rferj11-Nov-08 10:22
Rferj11-Nov-08 10:22 
AnswerRe: Adding events to objects in application.resources Pin
ColinM12311-Nov-08 11:19
ColinM12311-Nov-08 11:19 
GeneralUnable to upload file more than 35 kb using WCF Web service Pin
Vipul Mehta11-Nov-08 3:59
Vipul Mehta11-Nov-08 3:59 
QuestionRunning a method in secondary second of a storyboard ? Pin
Mohammad Dayyan10-Nov-08 22:51
Mohammad Dayyan10-Nov-08 22:51 
AnswerRe: Running a method in secondary second of a storyboard ? Pin
lneir12-Nov-08 19:09
lneir12-Nov-08 19:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.