In my application i'm trying to load the main module trough code. Everything works up to the point of rendering and i have NO clue why it isn't rendering. The content has the right values and everything.. My guess is that something went wibbly wobbly and I seem to be missing it.
Control that holds the view
[ContentPropertyAttribute("ContentView")]
public class ContentControlExtened : ContentControl
{
public static readonly DependencyProperty ContentProperty =
DependencyProperty.Register(
"Type",
typeof(Type),
typeof(ContentControl),
new FrameworkPropertyMetadata(null, ContentTypeChanged));
public static readonly DependencyProperty ContentViewProperty =
DependencyProperty.Register(
"View",
typeof(FrameworkElement),
typeof(ContentControl),
new FrameworkPropertyMetadata(null, ContentViewChanged));
private static void ContentViewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//throw new NotImplementedException();
}
public ContentControlExtened()
{
this.Loaded += ContentControlLoaded;
}
private void ContentControlLoaded(object sender, RoutedEventArgs e)
{
this.LoadContent();
}
private void LoadContent()
{
UserControl u = null;
if (Type != null)
{
u = (UserControl)ServiceLocator.Current.GetInstance(this.Type);
}
u.Background = new SolidColorBrush(Color.FromRgb(0, 0, 255));
this.View = u;
}
public Type Type
{
get { return (Type)GetValue(ContentProperty); }
set { SetValue(ContentProperty, value); }
}
public FrameworkElement View
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
}
}
}
Method in shell to load the main view of the given moduleInfo
private void OpenMainView(ModuleInfo module)
{
Type moduleType = Type.GetType(module.ModuleType);
var moduleMainViewType = moduleType.Assembly.GetType(moduleType.Namespace + ".Views.MainView");
this.ContentHolder.MainContent.Type = moduleMainViewType;
}
The contructor of the mainview is straight forward. Just standard control InitializeComponent() and Datacontext is being set trough the servicelocator.
public FrameworkElement View
{
get { return (FrameworkElement)GetValue(ContentProperty); }
set
{
SetValue(ContentProperty, value);
}
}
Here you are getting and setting the ContentProperty. It should be ContentViewProperty.
Related
It works when I bind directly to EventsSource but it doesn't when I change the binding to EventsView.
// EventsControl class
private bool Filter(object obj)
{
if (!(obj is Event #event)) return false;
if (string.IsNullOrEmpty(Location)) return true;
return true;
// return #event.Location == Location;
}
public static readonly DependencyProperty EventsSourceProperty = DependencyProperty.Register(
nameof(EventsSource), typeof(ObservableCollection<Event>), typeof(EventsControl), new PropertyMetadata(default(ObservableCollection<Event>), EventsSourceChanged));
public ObservableCollection<Event> EventsSource
{
get => (ObservableCollection<Event>)GetValue(EventsSourceProperty);
set => SetValue(EventsSourceProperty, value);
}
public ICollectionView EventsView { get; set; }
private static void EventsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (!(d is EventsControl eventsControl)) return;
var view = new CollectionViewSource { Source = e.NewValue }.View;
view.Filter += eventsControl.Filter;
eventsControl.EventsView = view;
//view.Refresh();
}
What could be wrong with this code?
I don't want to use a default view (
WPF CollectionViewSource Multiple Views? )
I made it a dependency property and it works. Not sure if that's the best way to solve it though.
public static readonly DependencyProperty EventsViewProperty = DependencyProperty.Register(
nameof(EventsView), typeof(ICollectionView), typeof(EventsControl), new PropertyMetadata(default(ICollectionView)));
public ICollectionView EventsView
{
get => (ICollectionView) GetValue(EventsViewProperty);
set => SetValue(EventsViewProperty, value);
}
I have trying to learn about EventHandler and I have to use a notification project.
Here is the link of project :
https://codeload.github.com/mike-eason/WPF_ToastNotifications/zip/master
All I did is changing .Net-framework from 4.5 to 4
And I faced with this error:
My class cannot be used as type parameter 'TEventArgs' in the generic
type or method 'System.EventHandler'
ToastNotification Class:
[TemplatePart(Name = "PART_DismissButton", Type = typeof(Button))]
public class ToastNotification : ContentControl
{
public event EventHandler Dismissed;
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
public static readonly DependencyProperty TitleProperty =
DependencyProperty.Register("Title", typeof(string), typeof(ToastNotification));
public string Message
{
get { return (string)GetValue(MessageProperty); }
set { SetValue(MessageProperty, value); }
}
public static readonly DependencyProperty MessageProperty =
DependencyProperty.Register("Message", typeof(string), typeof(ToastNotification));
public ToastTypes ToastType
{
get { return (ToastTypes)GetValue(ToastTypeProperty); }
set { SetValue(ToastTypeProperty, value); }
}
public static readonly DependencyProperty ToastTypeProperty =
DependencyProperty.Register("ToastType", typeof(ToastTypes), typeof(ToastNotification), new PropertyMetadata(new PropertyChangedCallback(OnToastTypeChanged)));
private static void OnToastTypeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ToastNotification toast = (ToastNotification)d;
toast.RefreshBackgroundColour();
}
private void RefreshBackgroundColour()
{
switch (ToastType)
{
case ToastTypes.Success:
Background = ColourSuccess;
break;
case ToastTypes.Error:
Background = ColourDanger;
break;
case ToastTypes.Info:
Background = ColourInfo;
break;
case ToastTypes.Warning:
Background = ColourWarning;
break;
}
}
public bool IsPersistent
{
get { return (bool)GetValue(IsPersistentProperty); }
set { SetValue(IsPersistentProperty, value); }
}
public static readonly DependencyProperty IsPersistentProperty =
DependencyProperty.Register("IsPersistent", typeof(bool), typeof(ToastNotification));
public double FontSizeTitle
{
get { return (double)GetValue(FontSizeTitleProperty); }
set { SetValue(FontSizeTitleProperty, value); }
}
public static readonly DependencyProperty FontSizeTitleProperty =
DependencyProperty.Register("FontSizeTitle", typeof(double), typeof(ToastNotification));
public Brush ColourSuccess
{
get { return (Brush)GetValue(ColourSuccessProperty); }
set { SetValue(ColourSuccessProperty, value); }
}
public static readonly DependencyProperty ColourSuccessProperty =
DependencyProperty.Register("ColourSuccess", typeof(Brush), typeof(ToastNotification));
public Brush ColourDanger
{
get { return (Brush)GetValue(ColourDangerProperty); }
set { SetValue(ColourDangerProperty, value); }
}
public static readonly DependencyProperty ColourDangerProperty =
DependencyProperty.Register("ColourDanger", typeof(Brush), typeof(ToastNotification));
public Brush ColourInfo
{
get { return (Brush)GetValue(ColourInfoProperty); }
set { SetValue(ColourInfoProperty, value); }
}
public static readonly DependencyProperty ColourInfoProperty =
DependencyProperty.Register("ColourInfo", typeof(Brush), typeof(ToastNotification));
public Brush ColourWarning
{
get { return (Brush)GetValue(ColourWarningProperty); }
set { SetValue(ColourWarningProperty, value); }
}
public static readonly DependencyProperty ColourWarningProperty =
DependencyProperty.Register("ColourWarning", typeof(Brush), typeof(ToastNotification));
static ToastNotification()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ToastNotification), new FrameworkPropertyMetadata(typeof(ToastNotification)));
}
public ToastNotification()
{
this.Loaded += ToastNotification_Loaded;
}
private void ToastNotification_Loaded(object sender, RoutedEventArgs e)
{
Storyboard sb = this.FindResource("ToastScaleInStoryboard") as Storyboard;
Storyboard.SetTarget(sb, this);
sb.Begin();
}
public override void OnApplyTemplate()
{
ButtonBase PART_DismissButton = this.GetTemplateChild("PART_DismissButton") as ButtonBase;
if (PART_DismissButton != null)
PART_DismissButton.Click += OnDismissed;
base.OnApplyTemplate();
RefreshBackgroundColour();
}
protected void OnDismissed(object sender, RoutedEventArgs e)
{
var eh = Dismissed;
if (eh != null)
eh(this, EventArgs.Empty);
}
}
Toast Class:
internal class Toast
{
public event EventHandler<ToastNotification> ToastClosing;
private DispatcherTimer _Timer;
private ToastNotification _Notification;
public Toast(ToastNotification notification)
{
_Notification = notification;
_Notification.Dismissed += Notification_Dismissed;
}
private void Notification_Dismissed(object sender, EventArgs e)
{
OnToastClosing();
}
private void Timer_Tick(object sender, EventArgs e)
{
//Stop and close the window.
_Timer.Stop();
OnToastClosing();
}
public void Show(TimeSpan displayTime)
{
//Only start the timer if the notification is not persistent.
if (!_Notification.IsPersistent)
{
//Set up the timer
_Timer = new DispatcherTimer();
_Timer.Interval = displayTime;
_Timer.Tick += Timer_Tick;
//Start the timer
_Timer.Start();
}
}
protected void OnToastClosing()
{
//Unsubscribe from the on dismiss event first (to avoid memory leaks)
_Notification.Dismissed -= Notification_Dismissed;
var eh = ToastClosing;
if (eh != null)
eh(this, _Notification);
}
}
System.EventHandler<T> delegate was changed in .NET 4.5. Before 4.5 it has the following signature:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e)
where TEventArgs : EventArgs;
Starting with .NET 4.5 it has another definition:
public delegate void EventHandler<TEventArgs>(object sender, TEventArgs e);
Note that where ... part has been removed. So before .NET 4.5 the type you use for event handler argument should inherit from EventArgs. Your ToastNotification does not inherit from that class, so cannot be used, hence your compiler error. When project targets .NET 4.5+ - you can use any type there so it compiles fine.
You can change your ToastClosing to
public event Action<object, ToastNotification> ToastClosing;
and it will compile just fine.
public event Action<object, ToastNotification> ToastClosing;
I think the recommendation is to inherit 'EventArgs'.
public class MyEventArgs : EventArgs
{ }
public event EventHandler<MyEventArgs> MyEvent;
I use TestStack White framework to automate testing of a WPF Application
It needs to open modal window and access TextBox in it. Everything works well, but White can't find Textbox, although it finds other elements of window
I tried the following lines of code:
TestStack.White.UIItems.TextBox TextBox = CreateBranch.Get<TestStack.White.UIItems.TextBox>(SearchCriteria.byAutomationId("Title"));
where CreateBranch is modal window
I also tried (SearchCriteria.All), (SearchCriteria.ByControlType) and nothing works
Coded UI tool finds this element well by AutomationID, but I need to do it in White
UISpy and other similar tools recognize this control and see its AutomationID
This textbox is custom control, here's code for it, I changed namespace name for privacy:
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Interactivity;
using System.Windows.Media;
namespace Test.Wpf.Controls.XTextBox
{
[TemplatePart(Name = "PART_Watermark", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_Pasword", Type = typeof(TextBlock))]
public class XTextBox : TextBox
{
#region Static
static XTextBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(XTextBox), new FrameworkPropertyMetadata(typeof(XTextBox)));
}
#endregion //Static
#region Fields
private TextBlock PART_Watermark;
private TextBlock PART_Pasword;
#endregion //Fields
#region DependencyProperties
public static readonly DependencyProperty WatermarkProperty = DependencyProperty.Register(
"Watermark",
typeof(String),
typeof(XTextBox),
new PropertyMetadata(String.Empty));
public static readonly DependencyProperty WatermarkVerticalAlignmentProperty = DependencyProperty.Register(
"WatermarkVerticalAlignment",
typeof(VerticalAlignment),
typeof(XTextBox),
new PropertyMetadata(VerticalAlignment.Stretch));
public static readonly DependencyProperty WatermarkForegroundProperty = DependencyProperty.Register(
"WatermarkForeground",
typeof(Brush),
typeof(XTextBox),
new PropertyMetadata(new SolidColorBrush(Colors.Black)));
public static readonly DependencyProperty WatermarkFontSizeProperty = DependencyProperty.Register(
"WatermarkFontSize",
typeof(Double),
typeof(XTextBox),
new PropertyMetadata(12.0));
public static readonly DependencyProperty IsFloatingProperty = DependencyProperty.Register(
"IsFloating",
typeof(Boolean),
typeof(XTextBox),
new PropertyMetadata(false));
public static readonly DependencyProperty IsAccessNegativeProperty = DependencyProperty.Register(
"IsAccessNegative",
typeof(Boolean),
typeof(XTextBox),
new PropertyMetadata(true));
public static readonly DependencyProperty IsDigitOnlyProperty = DependencyProperty.Register(
"IsDigitOnly",
typeof(Boolean),
typeof(XTextBox),
new PropertyMetadata(false));
public static readonly DependencyProperty MaxValueProperty = DependencyProperty.Register(
"MaxValue",
typeof(Single),
typeof(XTextBox),
new PropertyMetadata(Single.NaN));
public static readonly DependencyProperty IsPasswordProperty = DependencyProperty.Register(
"IsPassword",
typeof(Boolean),
typeof(XTextBox),
new PropertyMetadata(false));
public static readonly DependencyProperty VisibilityMainTextProperty = DependencyProperty.Register(
"VisibilityMainText",
typeof(Visibility),
typeof(XTextBox),
new PropertyMetadata(Visibility.Visible));
#endregion //DependencyProperties
#region Properties
[Description("Gets or sets the watermark title")]
public String Watermark
{
get { return (String)GetValue(WatermarkProperty); }
set { SetValue(WatermarkProperty, value); }
}
[Description("Gets or sets the watermark vertical alignment")]
public VerticalAlignment WatermarkVerticalAlignment
{
get { return (VerticalAlignment)GetValue(WatermarkVerticalAlignmentProperty); }
set { SetValue(WatermarkVerticalAlignmentProperty, value); }
}
[Description("Gets or sets the watermark title color")]
public Brush WatermarkForeground
{
get { return (Brush)GetValue(WatermarkVerticalAlignmentProperty); }
set { SetValue(WatermarkVerticalAlignmentProperty, value); }
}
[Description("Gets or sets the watermark title font size")]
public Double WatermarkFontSize
{
get { return (Double)GetValue(WatermarkVerticalAlignmentProperty); }
set { SetValue(WatermarkVerticalAlignmentProperty, value); }
}
[Description("Gets or sets the textbox floating mode")]
public Boolean IsFloating
{
get { return (Boolean)GetValue(IsFloatingProperty); }
set { SetValue(IsFloatingProperty, value); }
}
[Description("Gets or sets the textbox access of negative values")]
public Boolean IsAccessNegative
{
get { return (Boolean)GetValue(IsAccessNegativeProperty); }
set { SetValue(IsAccessNegativeProperty, value); }
}
[Description("Gets or sets the textbox chars type")]
public Boolean IsDigitOnly
{
get { return (Boolean)GetValue(IsDigitOnlyProperty); }
set { SetValue(IsDigitOnlyProperty, value); }
}
[Description("Gets or sets the max input value (enable in digit mode only)")]
public Single MaxValue
{
get { return (Single)GetValue(MaxValueProperty); }
set { SetValue(MaxValueProperty, value); }
}
[Description("Gets or sets the textbox is passwordbox")]
public Boolean IsPassword
{
get { return (Boolean)GetValue(IsPasswordProperty); }
set { SetValue(IsPasswordProperty, value); }
}
public Visibility VisibilityMainText
{
get { return (Visibility)GetValue(VisibilityMainTextProperty); }
set { SetValue(VisibilityMainTextProperty, value); }
}
#endregion //Properties
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
PART_Watermark = GetTemplateChild("PART_Watermark") as TextBlock;
PART_Pasword = GetTemplateChild("PART_Pasword") as TextBlock;
SetWatermarkVisibility();
if (IsPassword)
{
VisibilityMainText = Visibility.Collapsed;
if (PART_Pasword != null)
{
PART_Pasword.Visibility = Visibility.Visible;
PART_Pasword.FontSize = 20;
}
}
else
{
VisibilityMainText = Visibility.Visible;
}
DataObject.AddPastingHandler(this, OnPaste);
}
protected void OnPaste(Object sender, DataObjectPastingEventArgs e)
{
try
{
var isText = e.SourceDataObject.GetDataPresent(DataFormats.UnicodeText, true);
if (!isText) return;
var text = e.SourceDataObject.GetData(DataFormats.UnicodeText) as String;
if (!String.IsNullOrEmpty(text))
{
if (IsDigitOnly)
{
if (!IsAccessNegative)
{
var ch = text[0];
if (ch == 45)
{
e.CancelCommand();
}
}
for (int i = 0; i < text.Length; i++)
{
if (i == 0)
{
if (IsAccessNegative && text[i] == 45)
{
continue;
}
}
if (!Char.IsDigit(text[0]))
e.CancelCommand();
}
}
}
}
catch (Exception)
{
// ignored
e.Handled = true;
}
}
protected override void OnTextChanged(TextChangedEventArgs e)
{
base.OnTextChanged(e);
SetWatermarkVisibility();
if (IsPassword)
{
PART_Pasword.Text = new String('•', Text.Length);
}
}
protected override void OnLostKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnLostKeyboardFocus(e);
SetWatermarkVisibility();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
if (PART_Watermark != null)
{
PART_Watermark.Visibility = Visibility.Hidden;
}
}
protected override void OnPreviewTextInput(TextCompositionEventArgs e)
{
base.OnPreviewTextInput(e);
if (e.Text.Length == 0)
{
e.Handled = true;
return;
}
if (IsDigitOnly)
{
var ch = e.Text[0];
if (!Char.IsDigit(ch) && ch != 8 && ch != 46)
{
if (!(IsAccessNegative && ch == 45))
e.Handled = true;
}
if (IsFloating)
{
if (ch == 46 && Text.IndexOf('.') != -1)
{
e.Handled = true;
return;
}
}
if (!IsAccessNegative)
{
if (ch == 45)
{
e.Handled = true;
}
}
}
}
#region Private
private void SetWatermarkVisibility()
{
if (PART_Watermark != null)
{
PART_Watermark.Visibility = (Text != String.Empty || IsKeyboardFocused)? Visibility.Hidden : Visibility.Visible;
}
}
#endregion
}
}
Screenshot from UISpy
Let me know if that works
TextBox = (TextBox)CreateBranch
.Get(SearchCriteria.ByAutomationId("Title").AndOfFramework(WindowsFramework.Wpf));
Edited after new source added
You have to create a specific AutomationPeer for your custom control and return it via the override of the method OnCreateAutomationPeer().
Your control is a subclass of the TextBox control so you can just return a new TextBoxAutomationPeer instance or create your custom AutomationPeer from it.
public class XTextBox : TextBox
{
...
protected override AutomationPeer OnCreateAutomationPeer()
{
return new XTextBoxAutomationPeer(this);
// or just use the TextBoxAutomationPeer
// return new TextBoxAutomationPeer(this);
}
...
}
The custom automation peer
public class XTextBoxAutomationPeer : TextBoxAutomationPeer
{
public XTextBoxAutomationPeer(XTextBox owner)
: base(owner)
{
}
protected override string GetClassNameCore()
{
return "XTextBox";
}
}
[SetUpFixture]
public class SETUP_THAT_WILL_GET_CALL_LATER
{
[OneTimeSetUp]
public void OneTimeSetUp()
{
var applicationDirectory = TestContext.CurrentContext.TestDirectory;
var applicationPath = Path.Combine(applicationDirectory, #"..\..\..\, "your debug folder path here", "your application.exe here");
Application = Application.Launch(applicationPath);
Thread.Sleep(2000);
Window = Application.GetWindow("Title of your application", InitializeOption.WithCache);
}
[OneTimeTearDown()]
public void OneTimeTearDown()
{
Window.Dispose();
Application.Dispose();
}
public static Application Application;
public static Window Window;
}
Then in your test
[Test]
public void yourtest()
{
var textBox = SETUP_THAT_WILL_GET_CALL_LATER.**Window.Get<TextBox>("Your textbox name here");**
}
I have to write an ExtendedStackPanel control which will have two dependency properties like this.
<ExtendedStackPanel IsReadOnly="{Binding Item.IsReadOnly, Mode=OneWay}" >
<TemplateTrue>
... control visible when isreadonly is true
</TemplateTrue>
<TemplateFalse>
... control visible when isreadonly is false
</TemplateFalse>
</ExtendedStackPanel>
I've written this to achieve the goal but it's not working.
public class ExtendedStackPanel : StackPanel
{
public ExtendedStackPanel()
: base()
{
this.Orientation = System.Windows.Controls.Orientation.Vertical;
}
#region IsReadOnly
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnReadOnlyChanged)));
static void OnReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var visible = (bool)e.NewValue;
var control = d as ExtendedStackPanel;
if (visible)
{
control.TemplateTrue.Visibility = Visibility.Visible;
control.TemplateFalse.Visibility = Visibility.Collapsed;
}
else
{
control.TemplateTrue.Visibility = Visibility.Collapsed;
control.TemplateFalse.Visibility = Visibility.Visible;
}
}
#endregion
#region TemplateTrue
public Control TemplateTrue
{
get { return (Control)GetValue(TemplateTrueProperty); }
set { SetValue(TemplateTrueProperty, value); }
}
public static readonly DependencyProperty TemplateTrueProperty =
DependencyProperty.Register("TemplateTrue", typeof(Control),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnTemplateTrueChanged)));
static void OnTemplateTrueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ExtendedStackPanel;
control.TemplateTrue.Visibility = control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
}
#endregion
#region TemplateFalse
public Control TemplateFalse
{
get { return (Control)GetValue(TemplateFalseProperty); }
set { SetValue(TemplateFalseProperty, value); }
}
public static readonly DependencyProperty TemplateFalseProperty =
DependencyProperty.Register("TemplateFalse", typeof(Control),
typeof(ExtendedStackPanel), new PropertyMetadata(new PropertyChangedCallback(OnTemplateFalseChanged)));
static void OnTemplateFalseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ExtendedStackPanel;
control.TemplateFalse.Visibility = !control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
}
#endregion
}
In my code, I have put a combobox control when IsReadOnly is set to false, and a simple textbox when IsReadOnly is set to true but nothing is displayed when code is run.
Help me please.
Finally, I choose to use a UserControl, in which I put two ContentControl.
In code behind of the UserControl, I write this:
public partial class ConditionalControl : UserControl, INotifyPropertyChanged
{
public ConditionalControl()
{
InitializeComponent();
this.IsReadOnly = false;
}
#region IsReadOnly
public bool IsReadOnly
{
get { return (bool)GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public static readonly DependencyProperty IsReadOnlyProperty =
DependencyProperty.Register("IsReadOnly", typeof(bool),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnReadOnlyChanged)));
static void OnReadOnlyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var visible = (bool)e.NewValue;
var control = d as ConditionalControl;
if (visible)
{
control.TemplateTrueContent.Visibility = Visibility.Visible;
control.TemplateFalseContent.Visibility = Visibility.Collapsed;
}
else
{
control.TemplateTrueContent.Visibility = Visibility.Collapsed;
control.TemplateFalseContent.Visibility = Visibility.Visible;
}
}
#endregion
#region TemplateFalse
public object TemplateFalse
{
get { return (object)GetValue(TemplateFalseProperty); }
set { SetValue(TemplateFalseProperty, value); }
}
public static readonly DependencyProperty TemplateFalseProperty =
DependencyProperty.Register("TemplateFalse", typeof(object),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnTemplateFalseChanged)));
static void OnTemplateFalseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ConditionalControl;
control.TemplateFalseContent.Visibility = !control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
control.OnPropertyChanged("TemplateFalse");
}
#endregion
#region TemplateTrue
public object TemplateTrue
{
get { return (object)GetValue(TemplateTrueProperty); }
set { SetValue(TemplateTrueProperty, value); }
}
public static readonly DependencyProperty TemplateTrueProperty =
DependencyProperty.Register("TemplateTrue", typeof(object),
typeof(ConditionalControl), new PropertyMetadata(new PropertyChangedCallback(OnTemplateTrueChanged)));
static void OnTemplateTrueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as ConditionalControl;
control.TemplateTrueContent.Visibility = control.IsReadOnly ? Visibility.Visible : Visibility.Collapsed;
control.OnPropertyChanged("TemplateTrue");
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
if (propertyName == "TemplateFalse")
{
this.TemplateFalseContent.Content = this.TemplateFalse;
}
if (propertyName == "TemplateTrue")
{
this.TemplateTrueContent.Content = this.TemplateTrue;
}
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Hope this will help someone.
I basically have the same problem as this guy here: Error: " 'Subjects' property was already registered by 'Period' " is raised when more than one control is placed on the form
The main difference between us is that I want to subscribe to an event that has access to the local instance when the xaml changes the property.
So I have my UserControl:
public partial class BoardSquare : UserControl
{
public BoardSquare()
{
InitializeComponent();
Location = new BoardLocation(Int32.MinValue, Int32.MinValue);
XPositionProperty =
DependencyProperty.Register("XPosition", typeof(int),
typeof(BoardSquare), new PropertyMetadata(
new PropertyChangedCallback((value, args) =>
{
Location.X = (int)args.NewValue;
resetBackgroundColorToPosition();
})));
YPositionProperty=
DependencyProperty.Register("YPosition", typeof(int),
typeof(BoardSquare), new PropertyMetadata(
new PropertyChangedCallback((value, args)=>
{
Location.Y = (int)args.NewValue;
resetBackgroundColorToPosition();
})));
}
private void resetBackgroundColorToPosition()
{
this.Background = (Brush)(new ColorEnumToBrushesConverter()).Convert(Location.GetSquareColor(), typeof(BlackWhiteColor), null, null);
}
public readonly DependencyProperty XPositionProperty;
public readonly DependencyProperty YPositionProperty;
public int XPosition
{
get
{
return (int)GetValue(XPositionProperty);
}
set
{
SetValue(XPositionProperty, value);
}
}
public int YPosition
{
get
{
return (int)GetValue(YPositionProperty);
}
set
{
SetValue(YPositionProperty, value);
}
}
public BoardLocation Location { get; set; }
}
Here is my XAML:
<local:BoardSquare Grid.Column="3" Grid.Row="0" XPosition="3" YPosition="0"/>
<local:BoardSquare Grid.Column="4" Grid.Row="0" XPosition="4" YPosition="0"/>
From what I understand, the solution is to make XPositionProperty static and then register it in a static constructor. My problem then is I can't access the local instance of the class when my PropertyChangeCallback event happens.
How can I set the property in the XAML and still get an on property changed event in the C# code?
Is there a better solution than dependency properties?
Below is the working code of BoardSquare after I implemented the answer.
public partial class BoardSquare : UserControl
{
static BoardSquare()
{
XPositionProperty =
DependencyProperty.Register("XPosition", typeof(int),
typeof(BoardSquare), new PropertyMetadata(
new PropertyChangedCallback((objectInstance, args) =>
{
BoardSquare boardSquare = (BoardSquare)objectInstance;
boardSquare.Location.X = (int)args.NewValue;
boardSquare.resetBackgroundColorToPosition();
})));
YPositionProperty =
DependencyProperty.Register("YPosition", typeof(int),
typeof(BoardSquare), new PropertyMetadata(
new PropertyChangedCallback((objectInstance, args) =>
{
BoardSquare boardSquare = (BoardSquare)objectInstance;
boardSquare.Location.Y = (int)args.NewValue;
boardSquare.resetBackgroundColorToPosition();
})));
}
public BoardSquare()
{
InitializeComponent();
Location = new BoardLocation(Int32.MinValue, Int32.MinValue);
}
private void resetBackgroundColorToPosition()
{
this.Background = (Brush)(new ColorEnumToBrushesConverter()).Convert(Location.GetSquareColor(), typeof(BlackWhiteColor), null, null);
}
public static readonly DependencyProperty XPositionProperty;
public static readonly DependencyProperty YPositionProperty;
public int XPosition
{
get
{
return (int)GetValue(XPositionProperty);
}
set
{
SetValue(XPositionProperty, value);
}
}
public int YPosition
{
get
{
return (int)GetValue(YPositionProperty);
}
set
{
SetValue(YPositionProperty, value);
}
}
public BoardLocation Location { get; set; }
}
The first argument of PropertyChangedCallback is the local instance (btw. you better name it obj than value to avoid confusion). You have to cast this DependencyObject to BoardSquare and that's all.
public static readonly DependencyProperty XPositionProperty =
DependencyProperty.Register("XPosition", typeof(int), typeof(BoardSquare),
new PropertyMetadata(new PropertyChangedCallback((obj, args) => {
BoardSquare bs = obj as BoardSquare;
bs.Location.X = (int)args.NewValue;
bs.resetBackgroundColorToPosition();
})));
If I understand your question correctly, you are trying to override already WPF certificate property with your own. I don't think that's necessary here. If XPosition is already WPF certificate property, all you have to do is create a property in your usercontrol with getter/setter with setter calling INotifypropertychanged. you don't need dependency property in this case unless you want only same name but behave differently, and why do you want that?.