【问题标题】:Assigning a collection of images to a code-behind property将图像集合分配给代码隐藏属性
【发布时间】:2016-10-24 13:53:53
【问题描述】:

好的,所以我几天来一直在努力弄清楚 XAML 是如何实际处理集合的,并且每次我尝试 DependencyProperty 方法时,该属性都是空的。当我使用 ObservableCollection 并在 XAML 中为其分配一个数组类型时,我收到一条消息,指出无法将类型 ArrayExtension 分配给集合或字典。

所以我现在正处于一个我不知道我不知道的地方,但我知道我的目标。

我想在代码隐藏中将 <Image /> 类型的多个元素分配给我的集合,并且我必须能够识别(最好是整数)集合中引用了哪个“图像”。

首选 XAML 格式。

<cc:MyControl.States>
    <Image Source="{StaticResource PointBulletIconImage}" />
    <Image Source="{StaticResource PointNumberIconImage}" />
</cc:MyControl.States>

所需的代码隐藏功能

this.Image = States[CurrentState];

【问题讨论】:

  • 欢迎来到 SO!我已从您的问题标题中删除了一个标签。请阅读here为什么。
  • 鉴于你的名字,我怀疑你想要的行为是根据状态属性显示不同的图标,在这种情况下,我会建议一个值转换器,你可以在其中输入状态并取回图像源或 URI然后只需将图像图像源绑定到状态属性

标签: c# wpf xaml collections


【解决方案1】:

您的控件应声明一个包含ImageSource 对象集合的属性,而不是图像控件的集合,例如

public partial class MyControl : UserControl
{
    public List<ImageSource> States { get; } = new List<ImageSource>();

    ...
}

您现在可以像这样在 XAML 中添加位图资源:

<cc:MyControl>
    <cc:MyControl.States>
        <StaticResource ResourceKey="PointBulletIconImage"/>
        <StaticResource ResourceKey="PointNumberIconImage"/>
    </cc:MyControl.States>
</cc:MyControl>

MyControl 的 XAML 将声明一个 Image 控件,例如命名为“图像”

<Image x:Name="image"/>

你可以在后面的代码中设置它的Source 属性,如下所示:

image.Source = States[0];

【讨论】:

  • 我完全不知道 StaticResource 可以用作元素。黑魔法伴侣。我会先尝试这个解决方案,如果它不起作用,我会在我回家时尝试 Mike T。我会尽快给您回复。如果您需要更多详细信息,请告诉我。
  • 所以,它在语法上是合理的,但由于某种原因,它仍然是一个空值。我编译了代码,由于某种原因,列表永远不会被填充。有一个依赖属性,我是独立的。
  • 也许你没有将依赖属性初始化为一个新的列表实例。不要通过属性元数据设置默认值,而是通过 MyControl 构造函数中的赋值来做到这一点。
  • 我以为通过注册依赖属性,就自动初始化了?
【解决方案2】:

好的,按照 Clemens 的建议,我想通了。问题是我没有“等待”直到元素被加载。它初始化组件,然后接收我忘记的值。因此,正在分配的值还不存在。 Clemen 使用 ImageSource 可观察集合的解决方案有效,但我不得不等到控件加载完毕。

public ImageSource ImageSource {
        get {
            return GetValue(ImageSourceProperty) as ImageSource;
        }
        set {
            SetValue(ImageSourceProperty, value);
        }
    }
    public ObservableCollection<ImageSource> States { get; } = new ObservableCollection<ImageSource>();

    public int CurrentState { get; set; }
    public static readonly DependencyProperty ImageSourceProperty  = DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(PointButton));
    public PointButton( ) {
        CurrentState = 0;
        InitializeComponent( );
        Loaded += PointButton_Loaded;
    }

    private void PointButton_Loaded(object sender, RoutedEventArgs e) {
        PreviewMouseUp += PointButton_MouseUp;
        UpdateLayout( );
        if(States == null)
            Console.WriteLine("States is null");
        else
            ImageSource = States[CurrentState];
    }

    private void PointButton_MouseUp(object sender, MouseButtonEventArgs e) {
        if(CurrentState == States.Count - 1)
            CurrentState = 0;
        else
            CurrentState += 1;
        ImageSource = States[CurrentState];
    }
}

XAML

<Button x:Class="Notes.Views.Controls.PointButton"
    x:Name="RootElement"
         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:Notes.Views.Controls"
         mc:Ignorable="d"
         d:DesignHeight="300" d:DesignWidth="300"
         >
<Button.Template>
    <ControlTemplate>
        <Image Source="{Binding ImageSource, ElementName=RootElement}" />
    </ControlTemplate>
</Button.Template>

所以,我得到了它的工作。谢谢大家的回复:)

【讨论】:

    【解决方案3】:

    鉴于您的名字,我怀疑您希望的行为是根据状态属性显示不同的图标,在这种情况下,您确实希望尽可能多地保留代码。

    我会建议一个值转换器,您可以在其中输入状态并取回图像源或 URI,然后只需将图像图像源绑定到状态属性

    这是一个完整的例子 注意:示例使用 c#6 语法

    WPF:
    
    <Window x:Class="WpfApplication1.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:local="clr-namespace:WpfApplication1"
            mc:Ignorable="d"
            Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <BitmapImage x:Key="img1" UriSource="someimg1.png" />
            <BitmapImage x:Key="img2" UriSource="someimg2.png" />
            <BitmapImage x:Key="img3" UriSource="someimg3.png" />
            <BitmapImage x:Key="img4" UriSource="someimg4.png" />
            <BitmapImage x:Key="img5" UriSource="someimg5.png" />
            <local:StateImageConverter 
                x:Key="StateImageConverter"
                State1Image="{StaticResource img1}"
                State2Image="{StaticResource img2}"
                State3Image="{StaticResource img3}"
                State4Image="{StaticResource img4}"
                State5Image="{StaticResource img5}"/>
        </Window.Resources>
        <Window.DataContext>
            <local:VeiwModel x:Name="viewModel" />
        </Window.DataContext>
        <StackPanel>
            <ComboBox ItemsSource="{Binding AllStates}" SelectedValue="{Binding State}"/>
            <Image Source="{Binding State, Converter={StaticResource StateImageConverter}}" />
        </StackPanel>
    </Window>
    

    代码:

    public enum States
    {
        State1,
        State2,
        State3,
        State4,
        State5,
    }
    
    public class StateImageConverter : IValueConverter
    {
        public ImageSource State1Image { get; set; }
        public ImageSource State2Image { get; set; }
        public ImageSource State3Image { get; set; }
        public ImageSource State4Image { get; set; }
        public ImageSource State5Image { get; set; }
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var state = value as States?;
            if(state.HasValue)
            {
                switch (state.Value)
                {
                    case States.State1:
                        return State1Image;
                    case States.State2:
                        return State2Image;
                    case States.State3:
                        return State3Image;
                    case States.State4:
                        return State4Image;
                    case States.State5:
                        return State5Image;
                    default:
                        throw new InvalidCastException();
                }
            }
            else
                throw new NotImplementedException();
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            //one way only
            throw new NotImplementedException();
        }
    }
    
    public class VeiwModel : System.ComponentModel.INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private States state;
    
        public States State
        {
            get { return state; }
            set
            {
                state = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("State"));
            }
        }
        public IEnumerable<States> AllStates=> Enum.GetValues(typeof(States)).OfType< States>();
    
    }
    

    或者,如果您不想使用命名属性,那么使用列表的变体将如下所示:

    public class StateImageConverter : IValueConverter
    {
        public ObservableCollection<ImageSource> Images { get; set; } = new ObservableCollection<ImageSource>();
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            var state = value as States?;
            if(state.HasValue)
            {
                return Images[(int)state.Value];
            }
            else
                throw new NotImplementedException();
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            //one way only
            throw new NotImplementedException();
        }
    }
    

    定义为

    <local:StateImageConverter 
                x:Key="StateImageConverter">
                <local:StateImageConverter.Images>
                    <BitmapImage UriSource="someimg1.png" />
                    <BitmapImage UriSource="someimg2.png" />
                    <BitmapImage UriSource="someimg3.png" />
                    <BitmapImage UriSource="someimg4.png" />
                    <BitmapImage UriSource="someimg5.png" />
                </local:StateImageConverter.Images>
            </local:StateImageConverter>
    

    【讨论】:

    • 假设地说,如果我想为各州使用一个集合,我该怎么做呢?
    • 抱歉,目前在我的 iPad 上打字。我的预期目标是有一个图像按钮,其中图像循环显示未确定数量的图像。每个图像都绑定一个状态,并且必须从外部读取状态。
    • 如果您的项目可以同时处于多个状态,那么您将拥有一个项目控件,例如列表视图,然后使用项目模板来定义绑定
    猜你喜欢
    • 2015-05-07
    • 1970-01-01
    • 2017-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 1970-01-01
    • 2016-09-05
    相关资源
    最近更新 更多