Where to set window property in XAML - wpf

I found some code for an attached property that will let me escape close a window called as a dialog here on SO.
But I can't figure out where to set the property.
This might be complicated by the fact that this is a RibbonWindow and not a normal Window but I don't think so.
The attached property will be ab:WindowService.EscapeClosesWindow="True". Where in the xaml should it go??
Cheers,
Berryl
ERROR
Unable to cast object of type
'Microsoft.Expression.Platform.WPF.InstanceBuilders.WindowInstance' to type
'Microsoft.Windows.Controls.Ribbon.RibbonWindow'.
at AttachedBehaviors.WindowService.OnEscapeClosesWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
The gist of the attached property is
private static void OnEscapeClosesWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
var target = (Window) d;
if (target != null)
target.PreviewKeyDown += Window_PreviewKeyDown;
}
/// <summary>Handle the PreviewKeyDown event on the window</summary>
private static void Window_PreviewKeyDown(object sender, KeyEventArgs e) {
var target = (Window) sender;
// If this is the escape key, close the window
if (e.Key == Key.Escape)
target.Close();
}
window xaml
<r:RibbonWindow x:Class="SCA.Presentation.Wpf.Views.TimeSheet.WeeklyTimeSheetView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local ="clr-namespace:SCA.Presentation.Wpf.Views.TimeSheet"
xmlns:ab="clr-namespace:SCA.Presentation.Wpf.AttachedBehaviors;assembly=Smack.Core.Presentation.Wpf"
xmlns:r="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
Background="{DynamicResource WaveWindowBackground}"
FontFamily="Arial" FontSize="12"
Width="900" Height="600"
ResizeMode="CanResizeWithGrip"
WindowStartupLocation="CenterScreen"
ab:WindowService.EscapeClosesWindow="True" <=== ERROR
>
<r:RibbonWindow.Resources>
<ResourceDictionary Source="TimesheetResources.xaml" />
</r:RibbonWindow.Resources>

I created a sample application to recreate that error you mentioned. And I failed to reproduce that error. It easily compiled in my app.
Can you check with a sample application and try to find any differences?
Recreation:
public static class WindowService
{
public static readonly DependencyProperty EscapeClosesWindowProperty = DependencyProperty.RegisterAttached(
"EscapeClosesWindow",
typeof(bool),
typeof(WindowService),
new FrameworkPropertyMetadata(false, new PropertyChangedCallback(OnEscapeClosesWindowChanged)));
public static bool GetEscapeClosesWindow(DependencyObject d)
{
return (bool)d.GetValue(EscapeClosesWindowProperty);
}
public static void SetEscapeClosesWindow(DependencyObject d, bool value)
{
d.SetValue(EscapeClosesWindowProperty, value);
}
private static void OnEscapeClosesWindowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Window target = (Window)d;
if (target != null)
{
target.PreviewKeyDown += new System.Windows.Input.KeyEventHandler(Window_PreviewKeyDown);
}
}
private static void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
Window target = (Window)sender;
if (e.Key == Key.Escape)
target.Close();
}
}
XAML:
<ribbon:RibbonWindow x:Class="WpfApplication1.RibbonWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
xmlns:local="clr-namespace:WpfApplication1"
local:WindowService.EscapeClosesWindow="True"
Title="RibbonWindow1"
x:Name="Window"
Width="640"
Height="480">
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<ribbon:Ribbon x:Name="Ribbon">
<ribbon:RibbonTab x:Name="HomeTab"
Header="Home">
<ribbon:RibbonGroup x:Name="Group1"
Header="Group1"></ribbon:RibbonGroup>
</ribbon:RibbonTab>
</ribbon:Ribbon>
</Grid>
</ribbon:RibbonWindow>

Related

WPF Popup wrapping when dragging vertically

I have a project that uses a System.Windows.Controls.Primatives.Popup to drag a 'tooltip' like control along with a mouse.
Whenever the drag crosses a horizontal line the popup 'wraps' to the bottom of the screen - despite having sane values for the VerticalOffset. The point at which this wrapping occurs appears to be tied to the HEIGHT of the window, but not it's position.
Here's the code from the sandbox project I have created that also exhibits the same behavior:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.MainGrid.MouseDown += Grid_MouseDown;
this.MainGrid.MouseUp += Grid_MouseUp;
this.MainGrid.MouseMove += (s, e) => { if (this.Popup.IsOpen) { Popup_Drag(s, e); } };
this.Popup.MouseMove += Popup_Drag;
}
private void Popup_Drag(object sender, MouseEventArgs e)
{
Popup.HorizontalOffset = e.GetPosition(this.Popup).X;
Popup.VerticalOffset = e.GetPosition(this.Popup).Y;
this.Status_Top.Text = String.Format("Height/Top: {0}/{1} Width/Left: {2}/{3}", this.Height, this.Top, this.Width, this.Left);
this.Status.Text = String.Format("Vertical Offset: {0} Horizontal Offset: {1}", Popup.VerticalOffset, Popup.HorizontalOffset);
}
private void Grid_MouseUp(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = false;
}
private void Grid_MouseDown(object sender, MouseButtonEventArgs e)
{
this.Popup.IsOpen = true;
Popup_Drag(sender, e);
}
}
And the Window XAML:
<Window x:Class="WpfSandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="MainGrid" Background="Purple">
<TextBlock x:Name="Status_Top"></TextBlock>
<Popup x:Name="Popup" Cursor="Hand" HorizontalAlignment="Left"
VerticalAlignment="Bottom" IsOpen="True">
<TextBlock Background="Blue" Foreground="White">
<TextBlock x:Name="Status">TEXT</TextBlock></TextBlock>
</Popup>
</Grid>
</Window>
I was able to fix this by adding Placement="RelativePoint" to the Popup attributes. Apparently this is the default in Silverlight, but not WPF.

How can I "stick" a control on top edge of screen?

I have a custom control which shows some statistic data and need always be placed at the top edge of WP7 screen. but, when user inputs something on a textbox, the soft-keyboard popup. And the custom control is moved out of the screen. I want to make sure the custom control always visible, even when soft keyboard is popup. Does anyone know how to do this?
You must to use some "magic". By "magic" I mean RenderTransform.
Solution is simple - you need to move your custom control (down, when keyboard visible; up, when hidden). Check this valuable post - it's must help you.
Regards.
<phone:PhoneApplicationPage
x:Class="Test.Keyboard.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
>
<Grid x:Name="LayoutRoot" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="WINDOWS PHONE" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="developer's ?" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<Grid Grid.Row="1" Margin="12,0,12,0"></Grid>
<TextBox Grid.Row="2" LostFocus="TextBoxLostFocus"/>
</Grid>
</phone:PhoneApplicationPage>
public partial class MainPage : PhoneApplicationPage
{
private const double LandscapeShift = -259d;
private const double LandscapeShiftWithBar = -328d;
private const double Epsilon = 0.00000001d;
private const double PortraitShift = -339d;
private const double PortraitShiftWithBar = -408d;
public static readonly DependencyProperty TranslateYProperty = DependencyProperty.Register("TranslateY", typeof(double), typeof(MainPage), new PropertyMetadata(0d, OnRenderXPropertyChanged));
public MainPage()
{
InitializeComponent();
Loaded += MainPageLoaded;
}
public double TranslateY
{
get { return (double)GetValue(TranslateYProperty); }
set { SetValue(TranslateYProperty, value); }
}
private static void OnRenderXPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((MainPage)d).UpdateTopMargin((double)e.NewValue);
}
private void MainPageLoaded(object sender, RoutedEventArgs e)
{
BindToKeyboardFocus();
}
private void BindToKeyboardFocus()
{
PhoneApplicationFrame frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame != null)
{
var group = frame.RenderTransform as TransformGroup;
if (group != null)
{
var translate = group.Children[0] as TranslateTransform;
var translateYBinding = new Binding("Y");
translateYBinding.Source = translate;
SetBinding(TranslateYProperty, translateYBinding);
}
}
}
private void UpdateTopMargin(double translateY)
{
if (IsClose(translateY, LandscapeShift) || IsClose(translateY, PortraitShift)
||IsClose(translateY, LandscapeShiftWithBar) || IsClose(translateY, PortraitShiftWithBar)
)
{
LayoutRoot.Margin = new Thickness(0, -translateY, 0, 0);
}
}
private bool IsClose(double a, double b)
{
return Math.Abs(a - b) < Epsilon;
}
private void TextBoxLostFocus(object sender, RoutedEventArgs e)
{
LayoutRoot.Margin = new Thickness();
}
}
Good Luck....

Select parent ListBoxItem upon CheckBox interaction

Simple question though. I have a WPF application (.NET 4.0). There is a listbox which contains a number of userpanels. Each of these userpanels contains a checkbox.
When running you can click any portion of the userpanel except the checkbox itself and the listbox will select that row (which is indicated visually by the background changing in this simple case). If you check the box the row is not selected.
Requirement:
If you check the checkbox, this should count as selecting the row.
Checkbox Control:
<UserControl x:Class="CheckboxClickExample.CheckboxControl"
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"
d:DesignHeight="189" d:DesignWidth="221">
<Grid>
<CheckBox Content="CheckBox" Height="16" HorizontalAlignment="Left" Margin="10,10,0,0" Name="checkBox1" VerticalAlignment="Top" />
</Grid>
</UserControl>
Main Window:
<Window x:Class="CheckboxClickExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:checkboxsample="clr-namespace:CheckboxClickExample"
Title="MainWindow" Height="350" Width="525">
<ListBox>
<checkboxsample:CheckboxControl/>
<checkboxsample:CheckboxControl/>
<checkboxsample:CheckboxControl/>
<checkboxsample:CheckboxControl/>
</ListBox>
</Window>
You could handle this in your UserControl code behind:
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
var parent = sender as DependencyObject;
while (parent != null)
{
if (parent is Selector)
break;
parent = VisualTreeHelper.GetParent(parent);
}
if (parent != null)
((Selector) parent).SelectedItem = this;
}
And then use the handler in your CheckBox:
<CheckBox Content="CheckBox"
Height="16"
Click="ButtonBase_OnClick"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top" />
Edit
If you don't want to use code behind, the best I think you can do is to package the existing solution as an attached behaviour. This has the benefit that you only have to write the code once, and that the property can be set on any button even if it is not part of a UserControl.
For example:
public static class ButtonClickHelper
{
public static void SetEnableSelectionOnClick(ButtonBase button, bool value)
{
button.SetValue(EnableSelectionOnClickProperty, value);
}
public static bool GetEnableSelectionOnClick(ButtonBase button)
{
return (bool) button.GetValue(EnableSelectionOnClickProperty);
}
public static readonly DependencyProperty EnableSelectionOnClickProperty =
DependencyProperty.RegisterAttached("EnableSelectionOnClick", typeof (bool), typeof (ButtonClickHelper),
new FrameworkPropertyMetadata(OnEnableSelectionOnClickPropertyChanged));
private static void OnEnableSelectionOnClickPropertyChanged(DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
if (!(d is ButtonBase))
return;
var button = (ButtonBase) d;
if ((bool) e.NewValue)
{
button.Click += OnButtonClick;
}
else
{
button.Click -= OnButtonClick;
}
}
private static void OnButtonClick(object sender, RoutedEventArgs e)
{
var parent = sender as DependencyObject;
var ancestors = new List<DependencyObject>();
while (parent != null)
{
if (parent is Selector)
break;
parent = VisualTreeHelper.GetParent(parent);
ancestors.Add(parent);
}
if (parent != null)
{
var selector = (Selector) parent;
var itemToSelect = ancestors.Where(i => selector.Items.Contains(i)).FirstOrDefault();
if (itemToSelect != null)
((Selector) parent).SelectedItem = itemToSelect;
}
}
}
Then you can use this in your XAML by just setting the EnableSelectionOnClick dependency property:
<CheckBox Content="CheckBox"
Height="16"
l:ButtonClickHelper.EnableSelectionOnClick="True"
HorizontalAlignment="Left"
Margin="10,10,0,0"
VerticalAlignment="Top" />
Hope this helps!

DependencyProperty ... can set, but can't get value out via binding

I have a Window, containing a UserControl 'TemplateEditor'. The (shortened) TemplateEditor XAML is:
<UserControl x:Class="xxx.Windows.Core.Controls.TemplateEditor"
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"
x:Name="userControl">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBox Grid.Row="1" x:Name="textBox" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" />
</Grid>
</UserControl>
I want to be able to bind data through the TemplateEditor into the TextBox "textBox". I'm using a DependencyProperty to mask the TextBox in the code-behind:
namespace xxx.Windows.Core.Controls
{
public partial class TemplateEditor : UserControl
{
public string Text
{
get
{
string s=(string)GetValue(TextProperty);
return s;
}
set
{
if (Text != value)
{
SetValue(TextProperty, value);
}
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TemplateEditor),new PropertyMetadata(null,Text_PropertyChanged));
public TemplateEditor()
{
InitializeComponent();
}
private static void Text_PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
((TemplateEditor)source).textBox.Text = (string)e.NewValue;
}
}
}
So from that you can see I have a DependencyProperty Text that I have a callback on to pick up changes made by to the binding (say, from the ViewModel) and apply to the TextBox value.
This works.
The problem is, I can't seem to have the binding work in reverse, ie. to get the value back out of the Text property (and therefore the TextBox) and back in to the binding consumer (the ViewModel). I've debugged calling GetValue(TextProperty) and this returns the correct value so the DP dictionary is correctly updating.
Given the following Binding in the parent Window's XAML:
<src:ApplicationWindowBase x:Class="xxx.Windows.Client.Filing"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:src="clr-namespace:xxx.Windows.Core;assembly=MIGTurbo1.Windows.Core"
xmlns:viewmodel="clr-namespace:xxx.Windows.Client.ViewModel"
xmlns:converters="clr-namespace:xxx.Windows.Client.Converters"
xmlns:xxx_Windows_Core_Controls="clr-namespace:xxx.Windows.Core.Controls;assembly=xxx.Windows.Core"
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"
mc:Ignorable="d"
Title="File Item(s)" Height="450" Width="550" ShowInTaskbar="False">
<src:ApplicationWindowBase.Resources>
<viewmodel:ViewModelLocator x:Key="ViewModelLocator" d:IsDataSource="True"/>
<converters:FileableItemNameStringConverter x:Key="fileableItemNameStringConverter" />
<converters:FileableItemTypeStringConverter x:Key="fileableItemTypeStringConverter" />
<converters:FileableItemMetaDataStringConverter x:Key="fileableItemMetaDataStringConverter" />
<converters:FileableItemIconConverter x:Key="fileableItemIconConverter" />
</src:ApplicationWindowBase.Resources>
<src:ApplicationWindowBase.DataContext>
<Binding Mode="OneWay" Path="Filing" Source="{StaticResource ViewModelLocator}"/>
</src:ApplicationWindowBase.DataContext>
<Grid>
<!-- SNIP -->
<xxx_Windows_Core_Controls:TemplateEditor Grid.Column="1" Grid.Row="1" Margin="0" Text="{Binding Comment, Mode=TwoWay}" d:LayoutOverrides="Width, Height"/>
<!-- SNIP -->
</src:ApplicationWindowBase>
I am using MVVM Light and the ViewModel does bind correctly. There are other control/field bindings (ommitted) that work fine. THe problem is that the Text property binding on the Comment ViewModel property is not working. I can set it fine (ie. set value in ViewModel, then bind) but the user-entered value in Text never goes into the ViewModel Comments property.
What am I doing wrong?
Try this:
<TextBox Text="{Binding ElementName=userControl,Path=Text,Mode=TwoWay}" />
and remove handlers.
Ok, typical StackOverflow usage pattern adopted.
I realised I am writing this one-way, have added a TextChanged event handler to update the dependency property.
public partial class TemplateEditor : UserControl
{
public string Text
{
get
{
string s=(string)GetValue(TextProperty);
return s;
}
set
{
if (Text != value)
{
SetValue(TextProperty, value);
}
}
}
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(TemplateEditor),new PropertyMetadata(null,Text_PropertyChanged));
public TemplateEditor()
{
InitializeComponent();
textBox.TextChanged += new TextChangedEventHandler(textBox_TextChanged);
}
private static void Text_PropertyChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
{
((TemplateEditor)source).textBox.Text = (string)e.NewValue;
}
void textBox_TextChanged(object sender, TextChangedEventArgs e)
{
Text = textBox.Text;
}
}
Thanks for your time, and apologies. :)

UserControl PreviewMouseLeftButtonUp problem

I have a UserControl in WPF. I also have a Borderless window. To move it- I use DragMove.
But- to get a click event in the user control- I use the PreviewMouseLeftButtonUp event and capture the mouse on UserControl_MouseEnter.
The problem is- that if I click the control, then move the window- the event can be triggered also when clicking near the control, not on it.
Here is my code:
UserControl1.xaml:
<UserControl x:Class="WpfApplication1.UserControl1"
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"
d:DesignHeight="300" d:DesignWidth="300" MouseEnter="UserControl_MouseEnter" MouseLeave="UserControl_MouseLeave">
<Grid>
</Grid>
</UserControl>
UserControl1.xaml.cs:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
CaptureMouse();
}
private void UserControl_MouseLeave(object sender, MouseEventArgs e)
{
ReleaseMouseCapture();
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" xmlns:my="clr-namespace:WpfApplication1" WindowStyle="None" MouseLeftButtonDown="Window_MouseLeftButtonDown">
<Grid>
<my:UserControl1 Margin="39,29,380,199" Background="Red" PreviewMouseLeftButtonUp="UserControl1_PreviewMouseLeftButtonUp">
</my:UserControl1>
</Grid>
</Window>
MainWindow.xaml.cs:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void Window_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragMove();
}
private void UserControl1_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
MessageBox.Show("Hello World");
}
}
If you run this app- you'll see that if you click on the control, then drag the window, then click near the control (the side may vary)- it will trigger the PreviewMouseLeftButtonUp event even though you didn't click on the control itself.
Any ideas how to solve this?
Thanks!
I asked around, and found that to solve the problem, I need to change the User control's events:
Instead of MouseLeave- I use MouseMove.
private void UserControl_MouseEnter(object sender, MouseEventArgs e)
{
if (this.IsEnabled)
CaptureMouse();
}
private void UserControl_MouseMove(object sender, MouseEventArgs e)
{
Point mouseposition = e.GetPosition(this);
if (mouseposition.X < 0 || mouseposition.Y < 0 || mouseposition.X > this.ActualWidth || mouseposition.Y > this.ActualHeight)
ReleaseMouseCapture();
}

Resources