简体   繁体   English

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

[英]C#, WPF, bind List<string> to DataGrid

I have trouble to bind a List to a DataGrid. 我无法将List绑定到DataGrid。 It should be as simple as possible. 它应该尽可能简单。 I'm new to WPF and this is for my personal education. 我是WPF的新手,这是我的个人教育。

I have a View(Editor),ViewModel(VMText) and a Data(JustText) class. 我有一个View(编辑器),ViewModel(VMText)和一个Data(JustText)类。

My source so far: 我的来源到目前为止:

JustText.cs 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 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 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 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
    }
}

I just want to show List which is created in VMText in one column in the DataGrid 我只想在DataGrid的一列中显示在VMText中创建的List

If you really want to use the grid to edit the items in Code , you need to rewrite your viewmodel to make that possible. 如果您真的想使用网格编辑Code的项目,则需要重写viewmodel以使其成为可能。 You can't give the grid a collection of strings. 您无法为网格提供字符串集合。 You have to give it a collection of some class that has a string property . 你必须给它一些具有字符串属性的类的集合。 That's the way WPF works. 这就是WPF的工作方式。

If you don't want to edit them, just put IsReadOnly="True" on the column and they'll be read-only. 如果您不想编辑它们,只需在列上放置IsReadOnly="True" ,它们将是只读的。

Also, all your bindings look like you're guessing haphazardly at what everything means. 此外,你所有的绑定看起来都像是在随意猜测一切意味着什么。

So here's an example of how to do what I think you're trying to do. 所以这是一个如何做我认为你想做的事情的例子。 I eliminated your Model.Text class to simplify things. 我删除了你的Model.Text类来简化操作。 You're in deep enough without it. 如果没有它你就足够深了。

ViewModels.cs 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 MainWindow.xaml.cs

public MainWindow()
{
    InitializeComponent();

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

MainWindow.xaml 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>

I guess you simply want to display the strings in the Code source collection property of the view model in the DataGrid. 我想你只是想在DataGrid中的视图模型的Code source collection属性中显示字符串。

You should then bind the ItemsSource property of the DataGrid to the Code source property of the view model and then bind the DataGridTextColumn to the strings in the Code list itself. 然后,您应该将DataGrid的ItemsSource属性绑定到视图模型的Code source属性,然后将DataGridTextColumn绑定到Code列表本身的字符串。 You just have to modify the XAML markup of your view a bit to be able to see the strings. 您只需稍微修改视图的XAML标记即可查看字符串。 Try this: 尝试这个:

<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>

You should implement INotifyPropertyChanged to notify binding that property changed. 您应该实现INotifyPropertyChanged以通知绑定该属性已更改。 Also for the collections look at ObservableCollection instead of List . 同样对于集合,请查看ObservableCollection而不是List

Bind VMText.Code to DataGrid ItemSource. 将VMText.Code绑定到DataGrid ItemSource。 You don't need to Inicialize DataGrid DataContract in View when you do it in code behind. 在后面的代码中执行它时,您不需要在View中Inicialize DataGrid DataContract。

ViewModel 视图模型

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;
    }
}

View 视图

<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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM