带图像的 WPF 用户控件 属性
WPF UserControl with Image Property
我有一个包含用户控件的用户控件库,可以为 windows 创建自定义标题栏。我已经为这个标题栏提供了两个依赖属性——Title 和 Icon,我希望在通过 DLL 使用控件时能够设置它们。
我的标题工作正常,所以当我设置 Window 的 ViewModel 的标题 属性 时,它会填充到标题栏中。但是,我无法让图像执行相同的操作。
我尝试了各种变体,并阅读了有关使用依赖属性的整个课程,但我似乎无法显示图像。我已尝试使用 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 作为图像 属性,但无济于事):
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 的代码,它保存了 mainwindow 的属性:
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));
}
}
}
最后,这是 mainwindow 背后的代码,它设置了与 MainViewModel 的绑定并初始化了 window:
public partial class MainWindow : Window
{
public MainView_Model MainView { get; set; }
public MainWindow()
{
MainView = new MainView_Model();
DataContext = MainView;
InitializeComponent();
}
}
老实说,我看不出这里遗漏/错误的地方是什么,我已经阅读了大量文章、问题和答案,它们基本上似乎在说我正在以正确的方式做事……那又怎样地球错了?
问题是您的 XAML 中有一个图像试图绑定到视图模型中的图像。 Image
之类的 GUI 对象在您的视图模型层中没有位置,将您的 Icon
依赖项 属性 更改为 ImageSource
类型并将您的 XAML 图像绑定到该类型相反。
您的绑定有误。如果您没有模板,则不应使用 TemplatedParent
。使用:
xmlns:local="clr-namespace:WPFLibrary.User_Controls"
<Image Grid.Column="1" Source="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:TitleBar}}"/>
我有一个包含用户控件的用户控件库,可以为 windows 创建自定义标题栏。我已经为这个标题栏提供了两个依赖属性——Title 和 Icon,我希望在通过 DLL 使用控件时能够设置它们。
我的标题工作正常,所以当我设置 Window 的 ViewModel 的标题 属性 时,它会填充到标题栏中。但是,我无法让图像执行相同的操作。
我尝试了各种变体,并阅读了有关使用依赖属性的整个课程,但我似乎无法显示图像。我已尝试使用 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 作为图像 属性,但无济于事):
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 的代码,它保存了 mainwindow 的属性:
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));
}
}
}
最后,这是 mainwindow 背后的代码,它设置了与 MainViewModel 的绑定并初始化了 window:
public partial class MainWindow : Window
{
public MainView_Model MainView { get; set; }
public MainWindow()
{
MainView = new MainView_Model();
DataContext = MainView;
InitializeComponent();
}
}
老实说,我看不出这里遗漏/错误的地方是什么,我已经阅读了大量文章、问题和答案,它们基本上似乎在说我正在以正确的方式做事……那又怎样地球错了?
问题是您的 XAML 中有一个图像试图绑定到视图模型中的图像。 Image
之类的 GUI 对象在您的视图模型层中没有位置,将您的 Icon
依赖项 属性 更改为 ImageSource
类型并将您的 XAML 图像绑定到该类型相反。
您的绑定有误。如果您没有模板,则不应使用 TemplatedParent
。使用:
xmlns:local="clr-namespace:WPFLibrary.User_Controls"
<Image Grid.Column="1" Source="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:TitleBar}}"/>