简体   繁体   English

WPF将控件绑定到未知属性

[英]WPF binding a control to an unknown property

I'm quite new to WPF, and I'm trying to use a dataGrid . 我对WPF很陌生,并且正在尝试使用dataGrid Some of the data I'm trying to display is an image. 我尝试显示的某些数据是图像。 First I tried to just bind the data like this: 首先,我试图像这样绑定数据:

DataGrid.ItemsSource = <some collection>

this resulted with a column containing the path to the Image, not displaying the image. 这导致包含包含图像路径的列,而不显示图像。

I started googling around, and I came up with the following: 我开始四处搜寻,并提出以下建议:
I created a data template: 我创建了一个数据模板:

<DataTemplate x:Key="ImageDataTemplate">
    <Image Source="{Binding Image}"/>
</DataTemplate>

I added to the AutoGeneratingColumn event a function, and there I put the following code: 我向AutoGeneratingColumn事件添加了一个函数,并在其中放置了以下代码:

if (typeof(System.Windows.Media.ImageSource).IsAssignableFrom(e.PropertyType))
{
    DataGridTemplateColumn dgtc = new DataGridTemplateColumn();
    dgtc.Header = e.Column.Header;
    dgtc.CellTemplate = this.FindResource("ImageDataTemplate") as DataTemplate;

    e.Column = dgtc;
}

witch works fine, as long I call all Image properties in my classes Image is there a way to be a bit more flexible? 只要我在类中调用所有Image属性,女巫就可以正常工作Image是否可以灵活一些? (I want a few images in a class, or having a meaning full name for the image property, and I don't like almost duplicated code) (我需要一个类中的一些图像,或者具有image属性的含义全名,而且我不喜欢几乎重复的代码)

Maybe you could use a DataTemplateSelector? 也许您可以使用DataTemplateSelector?

Have a look at this article: http://tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector 看一下这篇文章: http : //tech.pro/tutorial/807/wpf-tutorial-how-to-use-a-datatemplateselector

That is a very misleading title you have there, seeing the word 'unknown' is nowhere in your question. 那是一个很容易让人误解的标题,看到“未知”一词在您的问题中无处不在。 Either way, the DataGrid is a somewhat complicated control and you seem to be looking at it from a WinForms point of view, by manipulating it using C# code, rather than simply defining how you want it to look in XAML, as is customary in WPF. 无论哪种方式, DataGrid都是一个有点复杂的控件,您似乎是从WinForms的角度来看它,方法是使用C#代码进行操作,而不是像WPF中那样简单地定义您希望它在XAML中的外观。 。

I would strongly recommend that you read some tutorials on how to use it in a WPF way before you continue... there are many such tutorials out there, but the WPF DataGrid Control one on WPF Tutorials.NET is a good one to start with. 我强烈建议您在继续之前阅读一些有关如何以WPF方式使用它的教程...那里有很多这样的教程,但是WPF Tutorials.NET上的WPF DataGrid Control是一个很好的起点。 。

In short, you can define what the contents of each column will look like in XAML... from the linked tutorial: 简而言之,您可以从链接的教程中定义每列在XAML中的内容...

<DataGrid ItemsSource="{Binding Customers}" AutoGenerateColumns="False" >
    <DataGrid.Columns>
        <DataGridTemplateColumn Header="Image" Width="SizeToCells" IsReadOnly="True">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Image Source="{Binding Image}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

I personally would set the AutoGenerateColumns property of the datagrid to false , and manually create the columns in XAML. 我个人将datagrid的AutoGenerateColumns属性设置为false ,并在XAML中手动创建列。

AutoGenerateColumns isn't that useful IMO. AutoGenerateColumns不是那么有用的IMO。 You often have properties in your model you don't wont to show in a column, and if it ends up by a handler for the AutoGeneratingColumn event, you just lose the benefit of not writing code for columns display. 您通常会在模型中拥有一些属性,而这些属性不会显示在列中,如果该AutoGeneratingColumnAutoGeneratingColumn事件的处理程序结尾,那么您将失去不编写用于列显示的代码的好处。

You can bind your data grid to an observable collection and construct the collection like this... 您可以将数据网格绑定到可观察的集合,并像这样构造集合...

public class ViewModel : INotifyPropertyChanged
{
    public ObservableCollection<ImageContainer> MyImageCollection { get; set; }
    public ViewModel()
    {
        MyImageCollection = new ObservableCollection<ImageContainer>();
        MyImageCollection.Add(new ImageContainer{Source = xxx});
    }
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}
public class ImageContainer : INotifyPropertyChanged
{
    private BitmapImage _source;
    public BitmapImage Source
    {
        [DebuggerStepThrough]
        get { return _source; }
        [DebuggerStepThrough]
        set
        {
            if (value != _source)
            {
                _source = value;
                OnPropertyChanged("Source");
            }
        }
    }
    #region INotifyPropertyChanged Implementation
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string name)
    {
        var handler = System.Threading.Interlocked.CompareExchange(ref PropertyChanged, null, null);
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
    #endregion
}

This fragment of code defines an observable collection of images and the bound container for each image. 该代码段定义了可观察的图像集合以及每个图像的绑定容器。 As shown, the View Model constructor makes an instance of the collection and starts populating it with images. 如图所示,View Model构造函数创建该集合的一个实例,并开始用图像填充它。 The container class does not HAVE to implement INPC, but I don't know what you're doing with the images, so INPC (INotifyPropertyChanged) is included anyway. 容器类没有实现INPC,但我不知道你在与图像做什么,所以INPC(INotifyPropertyChanged的)无论如何包括在内。

The corresponding Xaml would look like this... 相应的Xaml看起来像这样...

    <DataGrid ItemsSource="{Binding MyImageCollection}" AutoGenerateColumns="False" >
        <DataGrid.Columns>
            <DataGridTemplateColumn>
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <Image Source="{Binding Source}" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
        </DataGrid.Columns>
    </DataGrid>

If you are reading the images from disk, a popular variant is to bind to the FileInfo class and use a converter to return the image. 如果要从磁盘读取图像,则一种流行的变体是绑定到FileInfo类并使用转换器返回图像。 This approach makes the View Model less cluttered, but either design will give what you're looking for. 这种方法使视图模型不那么混乱,但是任何一种设计都能满足您的需求。

Afterthought: if you are using the data grid solely for displaying your image collection, consider using an Items Control instead. 事后思考:如果仅将数据网格用于显示图像集,请考虑改用Items Control。 Doing this may avoid the data grid's overhead. 这样做可以避免数据网格的开销。

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

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