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.
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 a custom combobox in my WPF application and the combo box is not updating when my item source is updated after initial launch. The itemsSource is a custom observableDictionary. I've implemented INotifyPropertyChanged on my properties with my observableDictionary but it won't update. I've searched through every WPF propertychanged event not working on stack overflow and i'm looking for some assistance.
Custom Combobox Code:
<controls:MultiSelectComboBox Width="100" Height="30" Padding="0 10 0 0" Grid.Row="0" Grid.Column="1"
ItemsSource="{Binding Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnDataErrors=True,
Path=DataContext.OptionTeamMembersDictionary,
BindsDirectlyToSource=True,
RelativeSource={RelativeSource AncestorType={x:Type UserControl},Mode=FindAncestor}}"
SelectedItems="{Binding SelectedOptionTeamMembersDictionary, Mode=TwoWay}"
x:Name="TeamMemberDisplay"
ToolTip="{Binding Path=Text, RelativeSource={RelativeSource Self}}"/>
Properties and private variables:
private ObservableDictionary<string, object> _optionTeamMembersDictionary;
private ObservableDictionary<string, object> _selectedOptionTeamMembersDictionary;
public ObservableDictionary<string, object> OptionTeamMembersDictionary
{
get
{
return _optionTeamMembersDictionary;
}
set
{
_optionTeamMembersDictionary = value;
OnPropertyChanged("OptionTeamMembersDictionary");
}
}
public ObservableDictionary<string, object> SelectedOptionTeamMembersDictionary
{
get
{
return _selectedOptionTeamMembersDictionary;
}
set
{
_selectedOptionTeamMembersDictionary = value;
OnPropertyChanged("SelectedOptionTeamMembersDictionary");
}
}
I use a button to trigger a database pull which leads each row into an object and then populates the optionTeamMemberDictionary when it returns more then one row of data.
All of the above works when the data is loaded in my constructor but when its loaded after launch my comboboxes do not show the new data in the collection.
EDIT:
Code for the Custom ComboBox being used:
https://www.codeproject.com/Articles/563862/Multi-Select-ComboBox-in-WPF is the URL this came from. Some edits were made to implement an obserableDirctionary instead of normal dictionary
public partial class MultiSelectComboBox : UserControl
{
private ObservableCollection<Node> _nodeList;
public MultiSelectComboBox()
{
InitializeComponent();
_nodeList = new ObservableCollection<Node>();
}
#region Dependency Properties
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnItemsSourceChanged)));
public static readonly DependencyProperty SelectedItemsProperty =
DependencyProperty.Register("SelectedItems", typeof(ObservableDictionary<string, object>), typeof(MultiSelectComboBox), new FrameworkPropertyMetadata(null,
new PropertyChangedCallback(MultiSelectComboBox.OnSelectedItemsChanged)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public static readonly DependencyProperty DefaultTextProperty =
DependencyProperty.Register("DefaultText", typeof(string), typeof(MultiSelectComboBox), new UIPropertyMetadata(string.Empty));
public ObservableDictionary<string, object> ItemsSource
{
get { return (ObservableDictionary<string, object>)GetValue(ItemsSourceProperty); }
set
{
SetValue(ItemsSourceProperty, value);
}
}
public ObservableDictionary<string, object> SelectedItems
{
get { return (ObservableDictionary<string, object>)GetValue(SelectedItemsProperty); }
set
{
SetValue(SelectedItemsProperty, value);
}
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string DefaultText
{
get { return (string)GetValue(DefaultTextProperty); }
set { SetValue(DefaultTextProperty, value); }
}
#endregion
#region Events
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.DisplayInControl();
}
private static void OnSelectedItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
control.SelectNodes();
control.SetText();
}
private void CheckBox_Click(object sender, RoutedEventArgs e)
{
CheckBox clickedBox = (CheckBox)sender;
if (clickedBox.Content == "All")
{
if (clickedBox.IsChecked.Value)
{
foreach (Node node in _nodeList)
{
node.IsSelected = true;
}
}
else
{
foreach (Node node in _nodeList)
{
node.IsSelected = false;
}
}
}
else
{
int _selectedCount = 0;
foreach (Node s in _nodeList)
{
if (s.IsSelected && s.Title != "All")
_selectedCount++;
}
if (_selectedCount == _nodeList.Count - 1)
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = true;
else
_nodeList.FirstOrDefault(i => i.Title == "All").IsSelected = false;
}
SetSelectedItems();
SetText();
}
#endregion
#region Methods
private void SelectNodes()
{
foreach (KeyValuePair<string, object> keyValue in SelectedItems)
{
Node node = _nodeList.FirstOrDefault(i => i.Title == keyValue.Key);
if (node != null)
node.IsSelected = true;
}
}
private void SetSelectedItems()
{
if (SelectedItems == null)
SelectedItems = new ObservableDictionary<string, object>();
SelectedItems.Clear();
foreach (Node node in _nodeList)
{
if (node.IsSelected && node.Title != "All")
{
if (this.ItemsSource.Count > 0)
SelectedItems.Add(node.Title, this.ItemsSource[node.Title]);
}
}
}
private void DisplayInControl()
{
_nodeList.Clear();
if (this.ItemsSource.Count > 0)
_nodeList.Add(new Node("All"));
foreach (KeyValuePair<string, object> keyValue in this.ItemsSource)
{
Node node = new Node(keyValue.Key);
_nodeList.Add(node);
}
MultiSelectCombo.ItemsSource = _nodeList;
}
private void SetText()
{
if (this.SelectedItems != null)
{
StringBuilder displayText = new StringBuilder();
foreach (Node s in _nodeList)
{
if (s.IsSelected == true && s.Title == "All")
{
displayText = new StringBuilder();
displayText.Append("All");
break;
}
else if (s.IsSelected == true && s.Title != "All")
{
displayText.Append(s.Title);
displayText.Append(',');
}
}
this.Text = displayText.ToString().TrimEnd(new char[] { ',' });
}
// set DefaultText if nothing else selected
if (string.IsNullOrEmpty(this.Text))
{
this.Text = this.DefaultText;
}
}
#endregion
}
public class Node : INotifyPropertyChanged
{
private string _title;
private bool _isSelected;
#region ctor
public Node(string title)
{
Title = title;
}
#endregion
#region Properties
public string Title
{
get
{
return _title;
}
set
{
_title = value;
NotifyPropertyChanged("Title");
}
}
public bool IsSelected
{
get
{
return _isSelected;
}
set
{
_isSelected = value;
NotifyPropertyChanged("IsSelected");
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
After much troubleshooting i was able to figure out an answer for this. onItemsSourceChanged was not firing after the control was instantiated so it never got updates made after initial launch of the application. I edited the OnItemsSourceChanged Function on the MultiFunctionComboBox to the below so it would fire on a changed event and it is working as expected now.
private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
MultiSelectComboBox control = (MultiSelectComboBox)d;
var action = new NotifyCollectionChangedEventHandler(
(o, args) =>
{
MultiSelectComboBox c = (MultiSelectComboBox)d;
c?.DisplayInControl();
});
if (e.OldValue != null)
{
var sourceCollection = (ObservableDictionary<string, object>)e.OldValue;
sourceCollection.CollectionChanged -= action;
}
if (e.NewValue != null)
{
var sourceCollection = (ObservableDictionary<string, object>)e.NewValue;
sourceCollection.CollectionChanged += action;
}
control.DisplayInControl();
}
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");**
}
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.
Has anyone had any luck applying the MahApps.Metro style to a NavigationWindow? I have implemented it for a Window just fine, but need to apply it to a NavigationWindow with Pages. I tried extending NavigationWindow and adding the modifications from MetroWindow like so, but no luck. The Window has a standard title bar and border, and the content is completely black.
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Navigation;
using MahApps.Metro.Native;
namespace MahApps.Metro.Controls
{
[TemplatePart(Name = PART_TitleBar, Type = typeof(UIElement))]
[TemplatePart(Name = PART_WindowCommands, Type = typeof(WindowCommands))]
public class MetroNavigationWindow : NavigationWindow
{
private const string PART_TitleBar = "PART_TitleBar";
private const string PART_WindowCommands = "PART_WindowCommands";
public static readonly DependencyProperty ShowIconOnTitleBarProperty = DependencyProperty.Register("ShowIconOnTitleBar", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty ShowTitleBarProperty = DependencyProperty.Register("ShowTitleBar", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty ShowMinButtonProperty = DependencyProperty.Register("ShowMinButton", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty ShowCloseButtonProperty = DependencyProperty.Register("ShowCloseButton", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty ShowMaxRestoreButtonProperty = DependencyProperty.Register("ShowMaxRestoreButton", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty TitlebarHeightProperty = DependencyProperty.Register("TitlebarHeight", typeof(int), typeof(MetroNavigationWindow), new PropertyMetadata(30));
public static readonly DependencyProperty TitleCapsProperty = DependencyProperty.Register("TitleCaps", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
public static readonly DependencyProperty SaveWindowPositionProperty = DependencyProperty.Register("SaveWindowPosition", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(false));
public static readonly DependencyProperty WindowPlacementSettingsProperty = DependencyProperty.Register("WindowPlacementSettings", typeof(IWindowPlacementSettings), typeof(MetroNavigationWindow), new PropertyMetadata(null));
public static readonly DependencyProperty TitleForegroundProperty = DependencyProperty.Register("TitleForeground", typeof(Brush), typeof(MetroNavigationWindow));
public static readonly DependencyProperty IgnoreTaskbarOnMaximizeProperty = DependencyProperty.Register("IgnoreTaskbarOnMaximize", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(false));
public static readonly DependencyProperty GlowBrushProperty = DependencyProperty.Register("GlowBrush", typeof(SolidColorBrush), typeof(MetroNavigationWindow), new PropertyMetadata(null));
public static readonly DependencyProperty FlyoutsProperty = DependencyProperty.Register("Flyouts", typeof(FlyoutsControl), typeof(MetroNavigationWindow), new PropertyMetadata(null));
public static readonly DependencyProperty WindowTransitionsEnabledProperty = DependencyProperty.Register("WindowTransitionsEnabled", typeof(bool), typeof(MetroNavigationWindow), new PropertyMetadata(true));
bool isDragging;
public bool WindowTransitionsEnabled
{
get { return (bool)this.GetValue(WindowTransitionsEnabledProperty); }
set { SetValue(WindowTransitionsEnabledProperty, value); }
}
public FlyoutsControl Flyouts
{
get { return (FlyoutsControl)GetValue(FlyoutsProperty); }
set { SetValue(FlyoutsProperty, value); }
}
public WindowCommands WindowCommands { get; set; }
public bool IgnoreTaskbarOnMaximize
{
get { return (bool)this.GetValue(IgnoreTaskbarOnMaximizeProperty); }
set { SetValue(IgnoreTaskbarOnMaximizeProperty, value); }
}
public Brush TitleForeground
{
get { return (Brush)GetValue(TitleForegroundProperty); }
set { SetValue(TitleForegroundProperty, value); }
}
public bool SaveWindowPosition
{
get { return (bool)GetValue(SaveWindowPositionProperty); }
set { SetValue(SaveWindowPositionProperty, value); }
}
public IWindowPlacementSettings WindowPlacementSettings
{
get { return (IWindowPlacementSettings)GetValue(WindowPlacementSettingsProperty); }
set { SetValue(WindowPlacementSettingsProperty, value); }
}
public bool ShowIconOnTitleBar
{
get { return (bool)GetValue(ShowIconOnTitleBarProperty); }
set { SetValue(ShowIconOnTitleBarProperty, value); }
}
public bool ShowTitleBar
{
get { return (bool)GetValue(ShowTitleBarProperty); }
set { SetValue(ShowTitleBarProperty, value); }
}
public bool ShowMinButton
{
get { return (bool)GetValue(ShowMinButtonProperty); }
set { SetValue(ShowMinButtonProperty, value); }
}
public bool ShowCloseButton
{
get { return (bool)GetValue(ShowCloseButtonProperty); }
set { SetValue(ShowCloseButtonProperty, value); }
}
public int TitlebarHeight
{
get { return (int)GetValue(TitlebarHeightProperty); }
set { SetValue(TitlebarHeightProperty, value); }
}
public bool ShowMaxRestoreButton
{
get { return (bool)GetValue(ShowMaxRestoreButtonProperty); }
set { SetValue(ShowMaxRestoreButtonProperty, value); }
}
public bool TitleCaps
{
get { return (bool)GetValue(TitleCapsProperty); }
set { SetValue(TitleCapsProperty, value); }
}
public SolidColorBrush GlowBrush
{
get { return (SolidColorBrush)GetValue(GlowBrushProperty); }
set { SetValue(GlowBrushProperty, value); }
}
public string WindowTitle
{
get { return TitleCaps ? Title.ToUpper() : Title; }
}
public MetroNavigationWindow()
{
Loaded += this.MetroWindow_Loaded;
}
private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
{
VisualStateManager.GoToState(this, "AfterLoaded", true);
if (!ShowTitleBar)
{
//Disables the system menu for reasons other than clicking an invisible titlebar.
IntPtr handle = new WindowInteropHelper(this).Handle;
UnsafeNativeMethods.SetWindowLong(handle, UnsafeNativeMethods.GWL_STYLE, UnsafeNativeMethods.GetWindowLong(handle, UnsafeNativeMethods.GWL_STYLE) & ~UnsafeNativeMethods.WS_SYSMENU);
}
if (this.Flyouts == null)
{
this.Flyouts = new FlyoutsControl();
}
}
static MetroNavigationWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MetroNavigationWindow), new FrameworkPropertyMetadata(typeof(MetroNavigationWindow)));
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
if (WindowCommands == null)
WindowCommands = new WindowCommands();
var titleBar = GetTemplateChild(PART_TitleBar) as UIElement;
if (ShowTitleBar && titleBar != null)
{
titleBar.MouseDown += TitleBarMouseDown;
titleBar.MouseUp += TitleBarMouseUp;
titleBar.MouseMove += TitleBarMouseMove;
}
else
{
MouseDown += TitleBarMouseDown;
MouseUp += TitleBarMouseUp;
MouseMove += TitleBarMouseMove;
}
}
protected override void OnStateChanged(EventArgs e)
{
if (WindowCommands != null)
{
WindowCommands.RefreshMaximiseIconState();
}
base.OnStateChanged(e);
}
protected void TitleBarMouseDown(object sender, MouseButtonEventArgs e)
{
var mousePosition = e.GetPosition(this);
bool isIconClick = ShowIconOnTitleBar && mousePosition.X <= TitlebarHeight && mousePosition.Y <= TitlebarHeight;
if (e.ChangedButton == MouseButton.Left)
{
if (isIconClick)
{
if (e.ClickCount == 2)
{
Close();
}
else
{
ShowSystemMenuPhysicalCoordinates(this, PointToScreen(new Point(0, TitlebarHeight)));
}
}
else
{
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
UnsafeNativeMethods.ReleaseCapture();
var wpfPoint = PointToScreen(Mouse.GetPosition(this));
short x = Convert.ToInt16(wpfPoint.X);
short y = Convert.ToInt16(wpfPoint.Y);
int lParam = x | (y << 16);
UnsafeNativeMethods.SendMessage(windowHandle, Constants.WM_NCLBUTTONDOWN, Constants.HT_CAPTION, lParam);
if (e.ClickCount == 2 && (ResizeMode == ResizeMode.CanResizeWithGrip || ResizeMode == ResizeMode.CanResize))
{
WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
}
}
}
else if (e.ChangedButton == MouseButton.Right)
{
ShowSystemMenuPhysicalCoordinates(this, PointToScreen(mousePosition));
}
}
protected void TitleBarMouseUp(object sender, MouseButtonEventArgs e)
{
isDragging = false;
}
private void TitleBarMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed)
{
isDragging = false;
}
if (isDragging
&& WindowState == WindowState.Maximized
&& ResizeMode != ResizeMode.NoResize)
{
// Calculating correct left coordinate for multi-screen system.
Point mouseAbsolute = PointToScreen(Mouse.GetPosition(this));
double width = RestoreBounds.Width;
double left = mouseAbsolute.X - width / 2;
// Check if the mouse is at the top of the screen if TitleBar is not visible
if (!ShowTitleBar && mouseAbsolute.Y > TitlebarHeight)
return;
// Aligning window's position to fit the screen.
double virtualScreenWidth = SystemParameters.VirtualScreenWidth;
left = left + width > virtualScreenWidth ? virtualScreenWidth - width : left;
var mousePosition = e.MouseDevice.GetPosition(this);
// When dragging the window down at the very top of the border,
// move the window a bit upwards to avoid showing the resize handle as soon as the mouse button is released
Top = mousePosition.Y < 5 ? -5 : mouseAbsolute.Y - mousePosition.Y;
Left = left;
// Restore window to normal state.
WindowState = WindowState.Normal;
}
}
internal T GetPart<T>(string name) where T : DependencyObject
{
return (T)GetTemplateChild(name);
}
private static void ShowSystemMenuPhysicalCoordinates(Window window, Point physicalScreenLocation)
{
if (window == null) return;
var hwnd = new WindowInteropHelper(window).Handle;
if (hwnd == IntPtr.Zero || !UnsafeNativeMethods.IsWindow(hwnd))
return;
var hmenu = UnsafeNativeMethods.GetSystemMenu(hwnd, false);
var cmd = UnsafeNativeMethods.TrackPopupMenuEx(hmenu, Constants.TPM_LEFTBUTTON | Constants.TPM_RETURNCMD, (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero);
if (0 != cmd)
UnsafeNativeMethods.PostMessage(hwnd, Constants.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero);
}
}
}
To accomplish this, I am using a MetroWindow as my main navigation window, and a Frame within that MetroWindow which handles the navigation.
Navigation Window
<Controls:MetroWindow x:Class="TestWpfApplicationMahApps.Metro.NavWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro" Title="NavWindow" Height="300" Width="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Frame Source="Page1.xaml" NavigationUIVisibility="Hidden"></Frame>
</Controls:MetroWindow>
This allows me to not change any of the navigation logic, it can be called from the NavigationService just like it was when using a NavigationWindow.
Page 1 .cs
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
NavigationService.Navigate(new Page2());
}
}