ComboBox的第二个Binding属性指向其第一个属性绑定对象

时间:2018-08-11 15:47:26

标签: c# wpf binding datagridtemplatecolumn

我试图解决这个问题长达1周,但我做不到!我正在搜索和阅读许多页面,其中包括:

(www.thomaslevesque.com) [WPF] HOW TO BIND TO DATA WHEN THE DATACONTEXT IS NOT INHERITED

(stackoverflow) How do I use WPF bindings with RelativeSource?

(stackoverflow) WPF - Binding error in DataGridComboboxColumn

(stackoverflow) WPF Error 40 BindingExpression path error: property not found on 'object'

我要做什么!?

我在SQL LocalDb中有一个域类和一个按TermType名称命名的表(您可以在下面看到其代码),具有5个属性:

  • TermTypeId
  • TypeName
  • 说明
  • 开始日期
  • EndDate

我的应用读取了TermType表,并且应该像这样在DataGrid中显示它们:

enter image description here

但是它不显示每种术语类型的开始/结束日期,因为它未能正确地绑定StartDate / EndDate属性!而且我还在Output窗口中收到此错误消息(不是异常):

System.Windows.Data Error: 40 : BindingExpression path error: 'StartDate' property not found on 'object' ''MonthName' (HashCode=38847270)'. BindingExpression:Path=StartDate; DataItem='MonthName' (HashCode=38847270); target element is 'ComboBox' (Name=''); target property is 'SelectedIndex' (type 'Int32')

在我说更多之前!请检查我与此窗口相关的UserControl xaml文件:

<UserControl x:Class="PresentationWPF.View.UserPanels.UserControlTermTypeCrud"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:PresentationWPF.View.UserPanels"
             xmlns:userPanels="clr-namespace:PresentationWPF.ViewModel.Client.UserPanels"
             xmlns:converters="clr-namespace:PresentationWPF.View.Converters"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800"
             Background="DarkSlateGray">
    <UserControl.Resources>
        <userPanels:TermTypeCrudViewModel x:Key="TermTypeCrudViewModel"/>
        <converters:IndexToMonthConverter x:Key="IndexToMonthConverter"/>
    </UserControl.Resources>

    <Grid DataContext="{StaticResource TermTypeCrudViewModel}">
        <Grid.RowDefinitions>
            <RowDefinition Height="9*"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <DataGrid ItemsSource="{Binding TermTypes}" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" >
            <!--
            <DataGrid.Resources>
                <userPanels:BindingProxy x:Key="MyProxy" Data="{Binding}"/>
            </DataGrid.Resources>
            -->
            <DataGrid.Columns>
                <DataGridTextColumn Header="Term Name" Binding="{Binding TypeName}" Width="120"/>
                <DataGridTextColumn Header="Description" Binding="{Binding Description}" Width="*"/>

                <DataGridTemplateColumn Header="Date Range" Width="150">
                    <DataGridTemplateColumn.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition/>
                                </Grid.ColumnDefinitions>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>
                                    <TextBlock  Grid.Column="0" Grid.Row="0" Text="Start: "/>
                                    <ComboBox  Grid.Column="1" Grid.Row="0" 
                                               Style="{StaticResource ComboBoxMonthNamesStyle}"
                                               SelectedIndex="{Binding StartDate,
                                                                Converter={StaticResource IndexToMonthConverter}}"
                                    />

                                    <TextBlock Grid.Column="0" Grid.Row="1" Text="End: "/>
                                    <ComboBox Grid.Column="1" Grid.Row="1" 
                                              Style="{StaticResource ComboBoxMonthNamesStyle}"
                                              SelectedIndex="{Binding EndDate, 
                                                                Converter={StaticResource IndexToMonthConverter}}"
                                    />
                            </Grid>
                        </DataTemplate>
                    </DataGridTemplateColumn.CellTemplate>
                </DataGridTemplateColumn>
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>

我知道ComboBox的问题在于它的第二个属性绑定SelectedIndex,它试图在StartDate对象而不是{内找到'MonthName'属性TermTypes中的{1}}。但是我不知道该怎么做!甚至我尝试在DataGrid ItemsSource="{Binding TermTypes}"属性绑定中使用RelativeSource,但可能无法正确使用!!!

如果在Visual Studio 2017中,我将鼠标悬停在SelectedIndex中的StartDate上,它也会显示此消息:

在类型为'PresentationWPF.View.UserPanels.TermTypeCrudViewModel'的数据上下文中无法解析属性'StartDate'

我什至尝试使用ComboBox(如我在乞求中的第一个链接中所建议),并且您可以看到我评论了Freezable class的这一行,但是即使我尝试在{ DataGrid.Resources对象的{1}},ComboBox仍为SelectedIndex属性未指向Data

注意: :我尝试在xaml的BindingProxy中直接插入月份名称(使用TermTypes),并省略ComboBox像下面的代码一样进行绑定,并且有效,但是我仍然想知道如何在以这种方式使用ComboBoxItem绑定时解决代码

Style

很高兴告诉我如何解决此问题!?

我是否以正确的方式使用了MVVM和UnitOfWork!?

还有更好的建议来替换App.xaml中的MonthName类或ComboBox样式!?

或者您在我的代码中可能看到的任何其他问题!? 非常感谢Advanced。

如果您需要查看/了解我的其他相关课程,并且...这里是:

TermType类:

Style

(模型)TermTypeCrudService类:

<ComboBox  Grid.Column="1" Grid.Row="0" 
           SelectedIndex="{Binding StartDate,
                            Converter={StaticResource IndexToMonthConverter}}"
>
    <ComboBoxItem>January</ComboBoxItem>
    <ComboBoxItem>February</ComboBoxItem>
    <ComboBoxItem>March</ComboBoxItem>
    <ComboBoxItem>April</ComboBoxItem>
    <ComboBoxItem>May</ComboBoxItem>
    <ComboBoxItem>June</ComboBoxItem>
    <ComboBoxItem>July</ComboBoxItem>
    <ComboBoxItem>August</ComboBoxItem>
    <ComboBoxItem>September</ComboBoxItem>
    <ComboBoxItem>October</ComboBoxItem>
    <ComboBoxItem>November</ComboBoxItem>
    <ComboBoxItem>December</ComboBoxItem>
</ComboBox>

(ViewModel)TermTypeCrudViewModel类:

namespace Core.BusinessLayer.Domain
{
    public partial class TermType
    {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
        public TermType()
        {
            Terms = new HashSet<Term>();
        }

        public int TermTypeId { get; set; }

        public string TypeName { get; set; }

        public string Description { get; set; }

        public DateTime? StartDate { get; set; }

        public DateTime? EndDate { get; set; }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
        public virtual ICollection<Term> Terms { get; set; }
    }
}

(查看-后面的代码)类:

namespace PresentationWPF.Model
{
    public class TermTypeCrudService : IDisposable
    {
        private readonly UnitOfWork _unitOfWork = new UnitOfWork(new AgsContext());
        public bool IsDbDirty = false;

        public IEnumerable<TermType> GetTermTypes() => _unitOfWork.TermTypes.GetAll();

        public void Dispose()
        {
            if (IsDbDirty)
                _unitOfWork.Complete();
            _unitOfWork.Dispose();
        }
    }
}

App.xaml文件:

namespace PresentationWPF.ViewModel.Client.UserPanels
{
    public class TermTypeCrudViewModel : INotifyPropertyChanged
    {
        private readonly TermTypeCrudService _termTypeCrudService = new TermTypeCrudService();

        private ObservableCollection<TermType> _termTypes;
        public ObservableCollection<TermType> TermTypes
        {
            get
            {
                return _termTypes;
            }
            set
            {
                _termTypes = value;
                OnPropertyChanged();
            }
        }

        public TermTypeCrudViewModel()
        {
               TermTypes = new ObservableCollection<TermType>(_termTypeCrudService.GetTermTypes());
        }
        public void Dispose() => _termTypeCrudService.Dispose();

        public event PropertyChangedEventHandler PropertyChanged;
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

MonthName类:

namespace PresentationWPF.View.UserPanels
{
    public partial class UserControlTermTypeCrud : IUserPanelNavigation
    {
        private readonly TermTypeCrudViewModel _termTypeCrudViewModel;

        public UserControlTermTypeCrud()
        {
            InitializeComponent();

            _termTypeCrudViewModel = FindResource("TermTypeCrudViewModel") as TermTypeCrudViewModel;
        }

        public ObservableCollection<TermType> TermTypes
        {
            get => (ObservableCollection<TermType>)_termTypeCrudViewModel.TermTypes;
            set => _termTypeCrudViewModel.TermTypes = value;
        }


        public event EventHandler OnNavigateEvent;
        public string Title => "Term Types";
        public UserControl NavigateToPanel { get; set; }

        public void Dispose()
        {
            _termTypeCrudViewModel.Dispose();
        }
    }
}

我在<Application x:Class="PresentationWPF.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PresentationWPF" xmlns:userPanels="clr-namespace:PresentationWPF.ViewModel.Client.UserPanels" Startup="Application_Startup"> <Application.Resources> <!-- Create Month names list to use in ComboBox --> <userPanels:MonthName x:Key="MonthName" /> <Style TargetType="ComboBox" x:Key="ComboBoxMonthNamesStyle"> <Setter Property="DataContext" Value="{StaticResource MonthName}"/> <Setter Property="ItemsSource" Value="{Binding MonthNamesCollection}"/> <Setter Property="Width" Value="100"/> </Style> </Application.Resources> </Application> namespace PresentationWPF.ViewModel.Client.UserPanels { public class MonthName { private ObservableCollection<string> _monthNamesCollection = new ObservableCollection<string>(); public ObservableCollection<string> MonthNamesCollection { get => _monthNamesCollection; set => _monthNamesCollection = value; } public MonthName() { MonthNamesCollection.Add("January"); // 31 days MonthNamesCollection.Add("February"); // 28 days in a common year and 29 days in leap years MonthNamesCollection.Add("March"); // 31 days MonthNamesCollection.Add("April"); // 30 days MonthNamesCollection.Add("May"); // 31 days MonthNamesCollection.Add("June"); // 30 days MonthNamesCollection.Add("July"); // 31 days MonthNamesCollection.Add("August"); // 31 days MonthNamesCollection.Add("September"); // 30 days MonthNamesCollection.Add("October"); // 31 days MonthNamesCollection.Add("November"); // 30 days MonthNamesCollection.Add("December"); // 31 days } } } 中使用的转换器类:

ComboBox

1 个答案:

答案 0 :(得分:1)

不要以组合框样式设置DataContext属性。这样做会破坏任何基于DataContext的绑定,例如{Binding StartDate}

<Style TargetType="ComboBox" x:Key="ComboBoxMonthNamesStyle">
    <Setter Property="ItemsSource"
            Value="{Binding MonthNamesCollection, Source={StaticResource MonthName}}"/>
    ...
</Style>