Question

I have a WPF 4 DataGrid whereby the first ComboBox changes what the second ComboBox is bound to by using a DataTemplateSelector keying off an id. For some strange reason, any cell in the second column, of the same type, seems to bind to the same value. I believe is related to using a DataTemplate, as I have seen this problem before, but obviously I am not understanding something I need to know.

Here is the code I assembled so far:

MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication1" Title="MainWindow" Height="300" Width="300"  Loaded="WindowLoaded">
    <Window.Resources>
        <CollectionViewSource x:Key="MainSource" />
        <CollectionViewSource x:Key="TypeSource" />
        <CollectionViewSource x:Key="DaysInMonthSource" />
        <CollectionViewSource x:Key="DaysInWeekSource" />

        <local:TypeSelector x:Key="cbTypeSelector">
            <local:TypeSelector.EmptyTemplate>
                <DataTemplate x:Name="Emptied">
                    <Grid></Grid>
                </DataTemplate>
            </local:TypeSelector.EmptyTemplate>
            <local:TypeSelector.DaysInWeekTemplate>
                <DataTemplate>
                    <ComboBox SelectedValue="{Binding Path=dayNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" 
                              ItemsSource="{Binding Source={StaticResource DaysInWeekSource}}" 
                              DisplayMemberPath="name" SelectedValuePath="id" Name="cb" Padding="3,2,3,3" />
                </DataTemplate>
            </local:TypeSelector.DaysInWeekTemplate>
            <local:TypeSelector.DaysInMonthTemplate>
                <DataTemplate>
                    <ComboBox SelectedValue="{Binding Path=dayNumber, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" 
                              ItemsSource="{Binding Source={StaticResource DaysInMonthSource}}" 
                              DisplayMemberPath="name" SelectedValuePath="id" Name="cb" Padding="3,2,3,3"  />
                </DataTemplate>
            </local:TypeSelector.DaysInMonthTemplate>
        </local:TypeSelector>
    </Window.Resources>
    <Grid>
        <DataGrid AutoGenerateColumns="False" Name="DataGrid1" CanUserAddRows="True" SelectionMode="Single" 
                   EnableColumnVirtualization="True" EnableRowVirtualization="True" >
            <DataGrid.Columns>
                <DataGridComboBoxColumn 
                    Header="Type" IsReadOnly="False"
                    DisplayMemberPath="name" SelectedValuePath="id" SelectedValueBinding="{Binding Path=type_id, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}"
                    ItemsSource="{Binding Source={StaticResource TypeSource}}">
                </DataGridComboBoxColumn>
                <DataGridTemplateColumn Header="Day" IsReadOnly="False">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <ContentPresenter local:Helper.UpdateTrigger="{Binding Path=type_id}" ContentTemplateSelector="{StaticResource cbTypeSelector}"/>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

MainWindow.xaml.cs

using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;

namespace WpfApplication1
{

    public class DayContainer
    {
        public int id { get; set; }
        public string type_id { get; set; }
        public string dayNumber { get; set; }
    }

    public class TypeSelector : DataTemplateSelector
    {
        public DataTemplate EmptyTemplate { get; set; }
        public DataTemplate DaysInWeekTemplate { get; set; }
        public DataTemplate DaysInMonthTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item, DependencyObject container)
        {
            var element = container as FrameworkElement;
            if (element == null || item == null) return EmptyTemplate;
            var dgr = FindVisualParent<DataGridRow>(element);
            var drv = dgr.Item as DayContainer;
            if (drv == null) return EmptyTemplate;
            if (drv.type_id == "1")
                return DaysInWeekTemplate;
            if (drv.type_id == "2")
                return DaysInMonthTemplate;
            return EmptyTemplate;
        }

        public static T FindVisualParent<T>(UIElement element) where T : UIElement
        {
            var parent = element;
            while (parent != null)
            {
                var correctlyTyped = parent as T;
                if (correctlyTyped != null) return correctlyTyped;
                parent = VisualTreeHelper.GetParent(parent) as UIElement;
            }
            return null;
        }
    }

    public class Helper
    {
        public static object GetUpdateTrigger(DependencyObject obj)
        {
            return obj.GetValue(UpdateTriggerProperty);
        }
        public static void SetUpdateTrigger(DependencyObject obj, object value)
        {
            obj.SetValue(UpdateTriggerProperty, value);
        }
        public static readonly DependencyProperty UpdateTriggerProperty =
            DependencyProperty.RegisterAttached("UpdateTrigger", typeof(object), typeof(Helper), new FrameworkPropertyMetadata(OnUpdateTriggerChanged));
        public static void OnUpdateTriggerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var cp = d as ContentPresenter;
            if (cp == null) return;
            var temp = cp.Content;
            cp.Content = null;
            cp.Content = temp;
        }
    }

    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void WindowLoaded(object sender, RoutedEventArgs e)
        {
            var source = (CollectionViewSource)FindResource("MainSource");
            source.Source = new List<DayContainer>
                                {
                                    new DayContainer {id = 1, type_id = "1", dayNumber = "1"},
                                    new DayContainer {id = 2, type_id = "1", dayNumber = "2"},
                                    new DayContainer {id = 3, type_id = "2", dayNumber = "3"},
                                };
            DataGrid1.ItemsSource = source.View;

            source = (CollectionViewSource)FindResource("TypeSource");
            if (source != null && source.Source == null)
                source.Source
                    = new[]
                          {
                              new {id = "1", name = "Week"},
                              new {id = "2", name = "Month"}
                          };


            source = (CollectionViewSource)FindResource("DaysInWeekSource");
            if (source != null && source.Source == null)
                source.Source
                    = new[]
                          {
                              new {id = "1", name = "Sunday"},
                              new {id = "2", name = "Monday"},
                              new {id = "3", name = "Tuesdsay"},
                              new {id = "4", name = "Wedsnesday"},
                              new {id = "5", name = "Thursday"},
                              new {id = "6", name = "Friday"},
                              new {id = "7", name = "Saturday"}
                          };


            source = (CollectionViewSource)FindResource("DaysInMonthSource");
            if (source != null && source.Source == null)
                source.Source = from n in Enumerable.Range(1, 31)
                                select new { id = n.ToString(CultureInfo.InvariantCulture), name = n.ToString(CultureInfo.InvariantCulture) };
        }
    }

}
Était-ce utile?

La solution

Found the solution in case it helps anyone.

Simply add IsSynchronizedWithCurrentItem="False" to each ComboBox.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top