C#,WPF,将List <string>绑定到DataGrid

时间:2016-12-29 14:19:46

标签: c# wpf xaml binding datagrid

我无法将List绑定到DataGrid。它应该尽可能简单。我是WPF的新手,这是我的个人教育。

我有一个View(编辑),ViewModel(VMText)和一个Data(JustText)类。

我的资料来源:

JustText.cs

namespace Model
{
    public class Text
    {
        private string _code;
        public string Code
        {
            get { return _code;  }
            set { _code = value; }
        }

        public Text()
        {
            _code = "Hello World!\nHow you doin'?";
        }
    } 
}

VMText.cs

namespace ViewModel
{
    public class VMText
    {    
        private Model.Text _code;

        public List<string> Code
        {            
            get { return new List<string>(_code.Code.Split('\n'));        }
            set { _code.Code = System.String.Join("\n", value.ToArray()); }
        }

        private View.Editor editor;

        public VMText(View.Editor editor)
        {
            _code = new Model.Text();
            this.editor = editor; 
        }
    }
}

Editor.xaml

<Window x:Class="View.Editor"
        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:local="clr-namespace:View"
        mc:Ignorable="d"
        Title="Editor" Height="240.024" Width="269.895">
    <Grid Background="#FF292929" Margin="0,0,-6.8,0.4">
        <DataGrid x:Name="dataGrid" 
                  HorizontalAlignment="Left" 
                  Margin="0,0,0,0" 
                  VerticalAlignment="Top"
                  Width="200pt"
                  Height="100pt"
                  DataContext="{Binding vmText}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Code, UpdateSourceTrigger=PropertyChanged}" Foreground="Black" Width="60" Header="Test" IsReadOnly="false" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

Editor.xaml.cs

namespace View
{
    public partial class Editor : Window
    {
        private ViewModel.VMText vmText;

        #region Constructor

        public Editor()
        {
            InitializeComponent();

            vmText = new ViewModel.VMText(this);
            DataContext = vmText;
        }

        #endregion
    }
}

我只想在DataGrid的一列中显示在VMText中创建的List

4 个答案:

答案 0 :(得分:6)

如果您确实想要使用网格编辑Code中的项目,则需要重写视图模型以使其成为可能。您无法为网格提供字符串集合。你必须给它一个具有字符串 property 的类的集合。这就是WPF的工作方式。

如果您不想编辑它们,只需将IsReadOnly="True"放在列上,它们将是只读的。

此外,你所有的绑定看起来都像是在随意猜测一切意味着什么。

所以这是一个如何做我想做想要做的事情的例子。我删除了你的Model.Text课来简化事情。如果没有它你就足够深了。

ViewModels.cs

namespace ViewModel
{
    #region ViewModelBase
    public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged([CallerMemberName] String propName = null)
            => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
        #endregion INotifyPropertyChanged
    }
    #endregion ViewModelBase


    //  This is the class we'll put in the grid. 
    public class CodeItem : ViewModelBase
    {
        private String _value = default(String);
        public String Value
        {
            get { return _value; }
            set
            {
                if (value != _value)
                {
                    _value = value;
                    OnPropertyChanged();
                }
            }
        }
    }

    public class VMText : ViewModelBase
    {
        public String CodeString
        {
            get {
                return String.Join("\n", Codes.Select(ci => ci.Value));
            }
            set
            {
                var q = (value ?? "")
                            .Split(new[] { '\n' })
                            .Select(s => new CodeItem { Value = s });
                Codes = new ObservableCollection<CodeItem>(q);
            }
        }

        #region Codes Property
        private ObservableCollection<CodeItem> _codes = default(ObservableCollection<CodeItem>);
        public ObservableCollection<CodeItem> Codes
        {
            get { return _codes; }
            set
            {
                if (value != _codes)
                {
                    _codes = value;
                    OnPropertyChanged();
                }
            }
        }
        #endregion Codes Property
    }
}

MainWindow.xaml.cs

public MainWindow()
{
    InitializeComponent();

    DataContext = new ViewModel.VMText
    {
        CodeString = "Hello World!\nHow you doin'?"
    };
}

MainWindow.xaml

<!-- 
Heights and widths in XAML aren't expressed in "pt" units.
That's CSS. Give XAML a floating point value with no unit specified.

Added AutoGenerateColumns="False" so you don't get a clone of the column 
with "Value" for a header. 
-->
<DataGrid 
    x:Name="dataGrid" 
    HorizontalAlignment="Left" 
    Margin="0,0,0,0" 
    VerticalAlignment="Top"
    ItemsSource="{Binding Codes}"
    AutoGenerateColumns="False"
    Width="200"
    Height="100"
    >
    <DataGrid.Columns>
        <!-- 
        Removed UpdateSourceTrigger=PropertyChanged because it has no effect. 
        Removed IsReadOnly="false" because it's the default already. 
        -->
        <DataGridTextColumn 
            Binding="{Binding Value}" 
            Width="120" 
            Header="Test"

            />
    </DataGrid.Columns>
</DataGrid>

答案 1 :(得分:4)

我想你只想在DataGrid中的视图模型的Code source collection属性中显示字符串。

然后,您应该将DataGrid的 ItemsSource 属性绑定到视图模型的Code source属性,然后将DataGridTextColumn绑定到Code列表本身的字符串。您只需稍微修改视图的XAML标记即可查看字符串。试试这个:

<DataGrid x:Name="dataGrid" 
              HorizontalAlignment="Left" 
              Margin="0,0,0,0" 
              VerticalAlignment="Top"
              Width="200pt"
              Height="100pt"
              ItemsSource="{Binding Code}"
              AutoGenerateColumns="False">
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding}" 
                                Foreground="Black" Width="60" Header="Test" IsReadOnly="false" />
    </DataGrid.Columns>
</DataGrid>

答案 2 :(得分:3)

您应该实现INotifyPropertyChanged以通知绑定该属性已更改。同样对于集合,请查看ObservableCollection而不是List

答案 3 :(得分:1)

将VMText.Code绑定到DataGrid ItemSource。当您在后面的代码中执行时,您不需要在View中Inicialize DataGrid DataContract。

<强>视图模型

namespace ViewModel
{
    public class VMText : INotifyPropertyChanged
    {
        public VMText(View.Editor editor)
        {
            _code = new Model.Text();
            this.editor = editor; 
        }

        public List<string> Code
        {            
            get
            {
                return new List<string>(_code.Code.Split('\n'));
            }
            set
            {
                _code.Code = System.String.Join("\n", value.ToArray());
                NotifyPropertyChanged("Code");
            }
        }

        private void NotifyPropertyChanged(String propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private Model.Text _code;

        private View.Editor editor;
    }
}

查看

<Window x:Class="View.Editor"
    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:local="clr-namespace:View"
    mc:Ignorable="d"
    Title="Editor" Height="240.024" Width="269.895">
<Grid Background="#FF292929" Margin="0,0,-6.8,0.4">
    <DataGrid x:Name="dataGrid" 
              HorizontalAlignment="Left" 
              Margin="0,0,0,0" 
              VerticalAlignment="Top"
              Width="200pt"
              Height="100pt"
              ItemsSource="{Binding Code}>
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Code"
                                Foreground="Black" Width="60"
                                Header="Test"
                                IsReadOnly="false" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>