【问题标题】:WPF UserControl with Image Property具有图像属性的 WPF 用户控件
【发布时间】:2019-09-17 23:41:55
【问题描述】:

我有一个包含用户控件的用户控件库,用于为窗口制作自定义标题栏。我给这个标题栏提供了两个依赖属性——标题和图标,当我通过 DLL 使用控件时,我希望能够设置它们。

我的标题工作正常,所以当我设置 Window 的 ViewModel 的 Title 属性时,它会填充到标题栏中。但是,我不能让图像做同样的事情。

我尝试了各种变体,并阅读了有关使用依赖属性的整个课程,但我似乎无法让图像显示。我曾尝试使用 ImageSource 属性、项目资源和图像,但我得到的只是一个空白。你能指出我解决问题的正确方向吗?

这是用户控件的 xaml(我读到我必须为 DP 使用 TemplatedParent RelativeSource,所以将其放入 - 我相信这将引用实现中的 MainViewModel):

<UserControl x:Class="WPFLibrary.User_Controls.TitleBar"
             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"
             mc:Ignorable="d">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/WPFLibrary;component/Styles/Buttons.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/WPFLibrary;component/Styles/Gradients.xaml"/>
                <ResourceDictionary Source="pack://application:,,,/WPFLibrary;component/Styles/Text.xaml"/>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <DockPanel VerticalAlignment="Top" Grid.Row="0" Grid.ColumnSpan="3"
               MouseDown="TitleBar_MouseDown"
               DataContext="{Binding}"
               Background="{StaticResource WindowTitleBar}">
        <Grid Grid.Row="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="30"/>
                <ColumnDefinition Width="5"/>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="90"/>
            </Grid.ColumnDefinitions>
            <Image Grid.Column="1" Source="{Binding Icon,RelativeSource={RelativeSource TemplatedParent}}"/>
            <TextBlock x:Name="Title_Bar"
                       Grid.Column="3"
                       Text="{Binding Title}"
                       Style="{StaticResource Text_WindowTitle}">
            </TextBlock>
            <!--StackPanel Containing the buttons excluded for SO Question-->
        </Grid>
    </DockPanel>
</UserControl>

这是同一控件背后的代码(根据其他一些 SO 答案,我尝试将项目资源和 ImageSource 用于 Image 属性,但无济于事):

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

namespace WPFLibrary.User_Controls
{
    /// <summary>
    /// Interaction logic for TitleBar.xaml
    /// </summary>
    public partial class TitleBar : UserControl, INotifyPropertyChanged
    {

        public Image Icon
        {
            get { return (Image)GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Icon.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(Image), typeof(TitleBar) );

        private static PropertyChangedEventArgs _stateChange = new PropertyChangedEventArgs("Windowstate");
        public WindowState _windowState;

        public WindowState Windowstate
        {
            get
            { return _windowState; }
            set
            {
                _windowState = value;
                NotifyChange(_stateChange);
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyChange(PropertyChangedEventArgs e)
        {
            PropertyChanged?.Invoke(this, e);
        }

        public TitleBar()
        {
            InitializeComponent();
        }

        //Button Click Methods excluded for SO question
    }
}

用于实现用户控件的 xaml 是这样的 - 我将绑定设置为 MainViewModel;具有设置属性的构造函数。

<Window x:Class="Demo_of_WPF_Library.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:uc="clr-namespace:WPFLibrary.User_Controls;assembly=WPFLibrary"
        xmlns:vm="clr-namespace:Demo_of_WPF_Library.ViewModel"
        mc:Ignorable="d"
        WindowStyle="None"
        BorderBrush="{StaticResource WindowBackgroundBrush}"
        x:Name="Main_Window"
        WindowState="{Binding Windowstate,ElementName=Titlebar}"
        Background="{StaticResource WindowBackgroundBrush}"
        Height="300" Width="800">
    <Window.DataContext>
        <vm:MainView_Model/>
    </Window.DataContext>
    <Grid>
        <uc:TitleBar Name="Titlebar" Icon="{Binding Icon}">
        </uc:TitleBar>
    </Grid>
</Window>

这是包含主窗口属性的 MainView_Model 的代码:

namespace Demo_of_WPF_Library.ViewModel
{
    public class MainView_Model
    {
        private string _title;
        public string Title
        {
            get { return _title; }
            set { _title = value; }
        }
        private Image _icon;

        public Image Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }

        public MainView_Model()
        {
            Title = "Demo WPF Library";
            Icon = new Image();
            Icon.Source = new BitmapImage(new Uri("/View/Images/IsItOk.ico",UriKind.Relative));
        }
    }
}

最后,这里是主窗口后面的代码,它设置绑定到 MainViewModel 并初始化窗口:

public partial class MainWindow : Window
{
    public MainView_Model MainView { get; set; }
    public MainWindow()
    {
        MainView = new MainView_Model();
        DataContext = MainView;
        InitializeComponent();
    }
}

老实说,我看不出这里缺少什么/错了,我已经阅读了大量文章、问题和答案,基本上似乎在说我正在以正确的方式做事......那么到底是什么错了吗?

【问题讨论】:

  • 我可能错过了你实际设置 Icon 属性的位置。还取决于你在哪里 MainView_Model 类需要实现 INofityPropertyChanged 我现在看到了。当你逐步完成它时,是 Icon.Source 设置?
  • 我以为我在 mainView_model 的构造函数中设置 Icon 属性...设置 Icon.Source 不是设置图像?我在 INotifyPropertyChange 实现中添加了,但这并没有解决问题。
  • 您是否逐步检查并确保 .Source 已设置?这有帮助吗? stackoverflow.com/a/12693661/3225
  • .Source 已设置,但所有其他属性均为默认值或为空。顺便说一下,图片是System.Windows.Controls.Image,而不是System.Drawing.Image。这让我非常焦虑,所以我想我会提到!
  • 我阅读了一个不同的 SO 答案并将构建操作设置为 Component!这两种方法我都试过了,都没有解决问题。

标签: wpf image user-controls dependency-properties


【解决方案1】:

您的绑定错误。如果您没有模板,则不应使用 TemplatedParent。使用:

xmlns:local="clr-namespace:WPFLibrary.User_Controls"
<Image Grid.Column="1" Source="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:TitleBar}}"/>

【讨论】:

  • 这个,结合@Mark Feldman 的回答已经解决了。我希望我可以将两个回复标记为答案!
  • @HighPlainsGrifter 很好看,我没注意到那个。
【解决方案2】:

问题是您的 XAML 中有一个图像,它试图绑定到您的视图模型中的图像。 Image 之类的 GUI 对象在您的视图模型层中没有位置,请将您的 Icon 依赖属性更改为 ImageSource 类型并将您的 XAML 图像绑定到它。

【讨论】:

  • 我不确定我是否完全理解如何实现它 - 我将 UserControl 中的 DP 类型更改为 ImageSource 并在视图模型中使用相同的类型,像以前一样使用 BitmapImage 设置源,但这没有用。我还将图像作为静态资源添加到 xaml 并将新的 ImageSource DP 绑定到该图像,但它也失败了。对不起,我想我把自己弄糊涂了。能不能说的详细一点?
  • 我已经尝试了更多的东西,现在我确定我不明白如何正确实现你描述的内容
  • 知道了!结合@Rekshino 的回答,这解决了它- 我把引用放在MainWindow.xaml.cs 中,而不是视图模型,并用它直接设置Titlebar.Icon = bitmap。我希望我可以将两个回复标记为答案!
猜你喜欢
  • 2013-12-05
  • 1970-01-01
  • 2014-10-09
  • 2014-08-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多