Search code examples
wpfbindingstyles

WPF UserControl Styling


I'm quite 'green' into WPF and I appreciate if you could share some starting point example or help me fixing my own code. I have tree UserControl (Component, ComponentTop, ComponentBottom) that share the same ViewModel class 'ComponentViewModel'. Instead of using this tree UserControl I would like to use just 'Component' to host the Style and DataContext (ComponentViewModel) and create 3 styles (Base,Top and Bottom) and then I just need to set Component.Style to alternate component visualization.

I've try to declare a style in a resource dictionary but the binding doesn't work. And from the UserControl I can set the style "Style={StaticResource Base}" but after building the project I get error code saying 'Resource not found'.

The Style:

<Style x:Key="Base" TargetType="UserControl">

    <Setter Property="ContentTemplate">
        <Setter.Value>
            <DataTemplate>
                <Border BorderThickness="0.5" BorderBrush="Gray">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition x:Name="Head" Height="Auto"/>
                            <RowDefinition x:Name="Content" Height="Auto"/>
                        </Grid.RowDefinitions>
                        <Border  Grid.Column="0"  Margin="1"  BorderThickness="0.25" BorderBrush="Black" Background="{Binding StatusColor}">

                            <Grid HorizontalAlignment="Stretch">
                                <TextBlock Margin="1,0,1,0" Text="{Binding Name, FallbackValue=######}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                                <Image   HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,0,1" Width="10" Height="10"  Source="{Binding PriorityImage}" Visibility="{Binding PriorityImageVisibility}"></Image>
                            </Grid>
                        </Border>

                        <Grid Grid.Row="1">

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="auto"/>
                                <ColumnDefinition Width="auto"/>
                            </Grid.ColumnDefinitions>

                            <layout:TagsContainer        Margin="2,0,0,0"  Grid.Column="0"  VerticalAlignment="Top" HorizontalAlignment="Left"    DataContext="{Binding TagsContainerDataContext}"/>

                            <layout:ControlTagsContainer Margin="5,0,2,0"  Grid.Column="1"  VerticalAlignment="Top" HorizontalAlignment="Left"    DataContext="{Binding ControlTagsContainerDataContext}"/>

                        </Grid>

                        <Image  Grid.Row="1"  Grid.RowSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="25" Height="25" MaxHeight="35" MaxWidth="35" Source="{Binding StatusImage}" Visibility="{Binding StatusImageVisibility}" ></Image>

                    </Grid>
                </Border>
            </DataTemplate>
            
        </Setter.Value>
        
    </Setter>

</Style>

The UserControl:

<UserControl
             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:ProjectX.UI.Layout"
             xmlns:ViewModels="clr-namespace:ProjectX.UI.Layout.ViewModels" 
             x:Class="ProjectX.UI.Layout.Component"
             mc:Ignorable="d" Cursor="" x:Name="Root" Height="auto" MinHeight="10" MinWidth="10" FontSize="10" Width="auto" Style="{ StaticResource Base }" >

<UserControl.DataContext>
    <ViewModels:ComponentViewModel/>
</UserControl.DataContext>

<UserControl.Resources>


    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source= "Components.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>

</UserControl.Resources>

TheViewModel:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ProjectX.Model.Component;
using DevExpress.Mvvm;
using System.Windows.Media;
using ProjectX.Model.Tag;
using ProjectX.UI.Tag;
using AppContext = ProjectX.Model.Tag.AppContext;
using System.Windows;
using System.Windows.Media.Imaging;
using ProjectX.Model.Component.Components;

namespace ProjectX.UI.Layout.ViewModels
{
    public class ComponentViewModel : ViewModelBase
    {
        private ComponentBase DataModel   = new ComponentBase();

        public string? Name
        {
            get { return GetValue<string>(); }
            private set { SetValue(value); }
        }

        public Brush StatusColor
        {
            get { return GetValue<Brush>(); }
            private set { SetValue(value); }
        }

        public ImageSource StatusImage
        {
            get { return GetValue<ImageSource>(); }
            private set { SetValue(value); }
        }

        public Visibility StatusImageVisibility
        {
            get { return GetValue<Visibility>(); }
            private set { SetValue(value); }
        }

        public ImageSource PriorityImage
        {
            get { return GetValue<ImageSource>(); }
            private set { SetValue(value); }
        }

        public Visibility PriorityImageVisibility
        {
            get { return GetValue<Visibility>(); }
            private set { SetValue(value); }
        }


        public Visibility SHControlsVisibility
        {
            get { return GetValue<Visibility>(); }
            private set { SetValue(value); }
        }

       public TagsContainerViewModel TagsContainerDataContext
        {
            get { return GetValue<TagsContainerViewModel>(); }
            private set { SetValue(value); }
        }

        public ControlTagsContainerViewModel ControlTagsContainerDataContext
        {
            get { return GetValue<ControlTagsContainerViewModel>();}

            private set { SetValue(value); }
        }



        private List<RuntimeTagViewModel>? Tags = null;        
        private List<RuntimeTagViewModel>? ControlTags = null; 



        public ComponentViewModel()
        {
            Name = "COMPONENT X";
            TagsContainerDataContext = new TagsContainerViewModel();
            ControlTagsContainerDataContext = new ControlTagsContainerViewModel();
            Init();
        }

        public ComponentViewModel(ComponentBase datamodel)
        {
            DataModel   = datamodel;
            Name        = datamodel.Label;
            Tags = DataModel.Tags.Where(x => x.AppContext == AppContext.Layout && x.Scope == Scope.User).Select(x => new RuntimeTagViewModel(x)).ToList();
            ControlTags = DataModel.Tags.Where(x => x.AppContext == AppContext.Control && x.Scope == Scope.User).Select(x => new RuntimeTagViewModel(x)).ToList();
            TagsContainerDataContext = new TagsContainerViewModel(Tags);
            ControlTagsContainerDataContext = new ControlTagsContainerViewModel(ControlTags);

            Init();
        }



        private void Init()
        {

            StatusColor = Brushes.Gray;
            SetStatusImage(StatusEnum.Warning);

            SHControlsVisibility   = Visibility.Collapsed;
            PriorityImageVisibility = Visibility.Collapsed;

            if (DataModel.Interface == nameof(IDamper))
            {
                PriorityImage = Global.Resources.Images.Priority;
                PriorityImageVisibility = Visibility.Visible;
            }

            if (DataModel.Interface == nameof(ISystemHandler))
            {
                SHControlsVisibility = Visibility.Visible;
            }

        }

        public void SetStatusImage(StatusEnum status = StatusEnum.None)
        {
            switch (status)
            {
                case StatusEnum.None:
                    StatusImage = Global.Resources.Images.Warning;
                    break;
                case StatusEnum.Error:
                    StatusImage = Global.Resources.Images.Error;
                    break;
                case StatusEnum.Warning:
                    StatusImage = Global.Resources.Images.Warning;
                    break;
                case StatusEnum.Info:
                    StatusImage = Global.Resources.Images.Info;
                    break;
                default:
                    throw new NotImplementedException();
            }


            if (status != StatusEnum.None)
            {
                StatusImageVisibility = Visibility.Visible;
            }
            else
            {
                StatusImageVisibility = Visibility.Hidden;
            }
        }

    }
}

Thank you!


Solution

  • After some time and research I fix the binding problem by using the following syntax:

    Background="{Binding DataContext.StatusColor, RelativeSource={RelativeSource AncestorType=layout:Component}}
    

    Instead of original one:

    Background="{Binding StatusColor}"