WPF UserControl со свойством изображения - PullRequest
0 голосов
/ 29 апреля 2019

У меня есть библиотека UserControl, содержащая пользовательский элемент управления для создания настраиваемой строки заголовка для окон.Я дал этой строке заголовка два свойства зависимостей - Title и Icon, которые я хотел бы установить, когда использую элемент управления через DLL.

У меня правильно работает заголовок, так что когда яустановите свойство Title в ViewModel окна, оно заполняется в строке заголовка.Тем не менее, я не могу заставить изображение делать то же самое.

Я перепробовал все виды вариаций и прочитал целый курс по использованию свойств зависимости, но я просто не могу заставить изображение отображаться.Я пытался использовать свойства ImageSource, ресурсы проекта и изображения, но все, что я получаю, это пустое место.Можете ли вы указать мне правильное направление, чтобы решить проблему?

Вот xaml для usercontrol (я читал, что мне пришлось использовать TemplatedParent RelativeSource для DP, так что это вставлено - я считаю, чтоэто будет ссылаться на 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 для реализации usercontrol выглядит так - я установил привязку к 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));
        }
    }
}

Наконец, вот код заmainwindow, которое устанавливает привязку к MainViewModel и инициализирует окно:

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

Честно говоря, я не вижу, что здесь отсутствует / неправильно, и я прочитал множество статей, вопросов и ответов, которые в основном кажутсясказать, что я все делаю правильно ... Так что, черт возьми, не так?

Ответы [ 2 ]

4 голосов
/ 29 апреля 2019

Ваша привязка неверна.Вы не должны использовать TemplatedParent, если у вас нет шаблона.Использование:

xmlns:local="clr-namespace:WPFLibrary.User_Controls"
<Image Grid.Column="1" Source="{Binding Icon, RelativeSource={RelativeSource AncestorType=local:TitleBar}}"/>
3 голосов
/ 29 апреля 2019

Проблема в том, что у вас есть изображение в вашем XAML, которое пытается привязаться к изображению в вашей модели представления. Объектам графического интерфейса, таким как Image, не место в слое модели представления, измените свойство зависимости Icon на тип ImageSource и вместо этого привяжите к нему свое изображение XAML.

...