如何在使用时将 DataGrids 分配给 WPF 中的用户控件?

How can I assign DataGrids to a user control in WPF at the point of use?

我正在尝试为典型的双列表情况定义一个用户控件(其中有两个并排的项目列表和按钮控件使一个项目的选定项目转移到另一个)。我不是很精通 WPF——我学到的大部分知识都是通过这样的网站零零碎碎地学来的。我了解到我可以为控件创建自定义依赖属性,这样我就可以推迟控件中项目(按钮、文本框等)的绑定,直到实际使用该控件为止,这很棒。但是,对于我的控件,我将拥有两个列表(可能是 DataGrids,因为到目前为止,我的大部分代码都涉及它们)但它们需要的不仅仅是绑定,所以我想做的是这样的:

    <MyUserControl . . . .>
        <DataGrid . . . .>
        <DataGrid . . . .>
    </MyUserControl>

但我不知道该怎么做。我认为可能有一些方法可以使用 ContentControls 作为 DataGrids 的替代品,然后以某种方式 link 将数据网格返回到用户控件中的内容控件,但我不太了解 Contentcontrols 和 none我发现使用它们的示例似乎完全适用于我想做的事情。

任何人都可以指出我正确的方向吗?谢谢。

我做了一些更多的研究,发现了一个有前途的方法,在这里: How to add controls dynamically to a UserControl through user's XAML?

我做了一个小型的概念验证项目,效果很好,所以我想在这里分享它。它使用 Galasoft 的 MVVM Light 框架。

我创建了一个带有文本块、ContentControl 和按钮的用户控件:

    <UserControl x:Class="DataGridInUserControlDemo.UserControls.DGPlusUC"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:ignore="http://www.galasoft.ch/ignore"
            mc:Ignorable="d ignore"
            x:Name="ControlRoot">
        <Grid DataContext="{Binding ElementName=ControlRoot}" Margin="10, 10, 10, 10" MinHeight="300" MinWidth="300">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="5*"/>
                <RowDefinition Height="2*"/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="{Binding Path=BannerText}" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="20"/>
            <ContentControl Grid.Row="1" Content="{Binding Path=InnerContent}" />
            <Button Grid.Row="2" x:Name="DemoButton" Content="{Binding Path=ButtonContent}" Command="{Binding Path=ButtonCommand}" Width="75" Height="25" HorizontalAlignment="Center" VerticalAlignment="Center" />
        </Grid>
    </UserControl>

我希望绑定到 UserControl 外部的属性本身绑定到自定义 DependencyProperty。

这是包含 DependencyProperty 定义的用户控件的代码隐藏:

    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;

    namespace DataGridInUserControlDemo.UserControls
    {
        public partial class DGPlusUC : UserControl
        {
            public DGPlusUC()
            {
                InitializeComponent();
            }

            public const string BannerTextPropertyName = "BannerText";

            public string BannerText
            {
                get
                {
                    return (string)GetValue(BannerTextProperty);
                }
                set
                {
                    SetValue(BannerTextProperty, value);
                }
            }

            public static readonly DependencyProperty BannerTextProperty = DependencyProperty.Register(
                BannerTextPropertyName,
                typeof(string),
                typeof(DGPlusUC));

            public const string ButtonContentPropertyName = "ButtonContent";

            public string ButtonContent
            {
                get
                {
                    return (string)GetValue(ButtonContentProperty);
                }
                set
                {
                    SetValue(ButtonContentProperty, value);
                }
            }

            public static readonly DependencyProperty ButtonContentProperty = DependencyProperty.Register(
                ButtonContentPropertyName,
                typeof(string),
                typeof(DGPlusUC));

            public const string ButtonCommandPropertyName = "ButtonCommand";

            public ICommand ButtonCommand
            {
                get
                {
                    return (ICommand)GetValue(ButtonCommandProperty);
                }
                set
                {
                    SetValue(ButtonCommandProperty, value);
                }
            }

            public static readonly DependencyProperty ButtonCommandProperty = DependencyProperty.Register(
                ButtonCommandPropertyName,
                typeof(ICommand),
                typeof(DGPlusUC));

            public const string InnerContentPropertyName = "InnerContent";

            public UIElement InnerContent
            {
                get
                {
                    return (UIElement)GetValue(InnerContentProperty);
                }
                set
                {
                    SetValue(InnerContentProperty, value);
                }
            }

            public static readonly DependencyProperty InnerContentProperty = DependencyProperty.Register(
                InnerContentPropertyName,
                typeof(UIElement),
                typeof(DGPlusUC));
        }
    }

这是主要的 XAML window:

    <Window x:Class="DataGridInUserControlDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:ignore="http://www.galasoft.ch/ignore"
            xmlns:demo="clr-namespace:DataGridInUserControlDemo.UserControls"
            mc:Ignorable="d ignore"
            Height="400"
            Width="400"
            Title="MVVM Light Application"
            DataContext="{Binding Main, Source={StaticResource Locator}}">

        <Window.Resources>
            <ResourceDictionary>
                <ResourceDictionary.MergedDictionaries>
                    <ResourceDictionary Source="Skins/MainSkin.xaml" />
                </ResourceDictionary.MergedDictionaries>
            </ResourceDictionary>
        </Window.Resources>
        <Grid x:Name="LayoutRoot">
            <demo:DGPlusUC BannerText="{Binding UCTitle}"  ButtonContent="{Binding ButtonText}" ButtonCommand="{Binding ButtonCommand}" HorizontalAlignment="Center" VerticalAlignment="Center">
                <demo:DGPlusUC.InnerContent>
                    <Grid DataContext="{Binding Main, Source={StaticResource Locator}}">
                        <DataGrid ItemsSource="{Binding Path=DataItems}" AutoGenerateColumns="True" />
                    </Grid>
                </demo:DGPlusUC.InnerContent>
            </demo:DGPlusUC>
        </Grid>
    </Window>

自定义 DependencyProperty 在控件中用作标记以绑定到 ViewModel 中的属性。

请注意括号中的 demo:DGPlusUC.InnerContent -- 这是 ContentControl 的替换代码所在的位置。嵌入的 UserControl 继承了 Window 的数据上下文,但出于某种原因,这部分没有,所以,在稍微试验之后,我只是举手明确地声明了数据上下文。

这是 ViewModel 代码:

    using GalaSoft.MvvmLight;
    using GalaSoft.MvvmLight.CommandWpf;
    using DataGridInUserControlDemo.Model;
    using System.Windows.Input;
    using System.Collections.ObjectModel;

    namespace DataGridInUserControlDemo.ViewModel
    {
        public class MainViewModel : ViewModelBase
        {
            private readonly IDataModel theModel;

            private ObservableCollection<DataItem> _DataItems;

            public ObservableCollection<DataItem> DataItems
            {
                get
                {
                    return _DataItems;
                }

                set
                {
                    if (_DataItems == value)
                    {
                        return;
                    }

                    var oldValue = _DataItems;
                    _DataItems = value;
                    RaisePropertyChanged(() => DataItems, oldValue, value, true);
                }
            }


            private string _ButtonText = "First";
            public string ButtonText
            {
                get
                {
                    return this._ButtonText;
                }

                set
                {
                    if (this._ButtonText == value)
                    {
                        return;
                    }

                    var oldValue = this._ButtonText;
                    this._ButtonText = value;
                    RaisePropertyChanged(() => ButtonText, oldValue, value, true);
                }
            }


            private string _UCTitle = string.Empty;
            public string UCTitle
            {
                get
                {
                    return this._UCTitle;
                }

                set
                {
                    if (this._UCTitle == value)
                    {
                        return;
                    }

                    var oldValue = this._UCTitle;
                    this._UCTitle = value;
                    RaisePropertyChanged(() => UCTitle, oldValue, value, true);
                }
            }

            private ICommand _ButtonCommand;
            public ICommand ButtonCommand
            {
                get
                {
                    return this._ButtonCommand;
                }

                set
                {
                    if (this._ButtonCommand == value)
                    {
                        return;
                    }

                    var oldValue = this._ButtonCommand;
                    this._ButtonCommand = value;
                    RaisePropertyChanged(() => ButtonCommand, oldValue, value, true);
                }
            }

            public MainViewModel(IDataModel model)
            {
                this.theModel = model;
                this._UCTitle = "DataGrid in User Control Demo";
                this._DataItems = new ObservableCollection<DataItem>(this.theModel.SomeData);
                this._ButtonCommand = new RelayCommand(this.ButtonCmd, () => { return true; }) ;
            }

            private void ButtonCmd()
            {
                if (this.ButtonText == "First")
                {
                    this.ButtonText = "Second";
                }
                else
                {
                    this.ButtonText = "First";
                }
            }
        }
    }

最后,结果如下:

DataGrid in UserControl Demo