WPF Ribbon Control - Change Content of a Ribbon Button - wpf

Is there any way to change the Content of a RibbonButton?
I know that a RibbonButton has an Image and a Label but I want a button with a shape (Rectangle class) in it's Content and this button should have the RibbonButton style applied. Is there any way to do that?

Why don't you create your own button control?
XAML:
<Button x:Class="MyApp.myButton"
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="71" d:DesignWidth="87">
<Rectangle Height="40" Width="40" Fill="#FFC11414" />
Code behind:
public partial class myButton : Button, IRibbonControl
{
public myButton()
{
InitializeComponent();
Type forType = typeof(myButton);
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(forType, new FrameworkPropertyMetadata(forType));
ButtonBase.CommandProperty.OverrideMetadata(forType, new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCommandChanged)));
FrameworkElement.ToolTipProperty.OverrideMetadata(forType, new FrameworkPropertyMetadata(null, new CoerceValueCallback(RibbonButton.CoerceToolTip)));
ToolTipService.ShowOnDisabledProperty.OverrideMetadata(forType, new FrameworkPropertyMetadata(true));
}
public static object CoerceToolTip(DependencyObject d, object value)
{
if (value == null)
{
RibbonButton button = (RibbonButton)d;
RibbonCommand command = button.Command as RibbonCommand;
if ((command == null) || ((string.IsNullOrEmpty(command.ToolTipTitle) && string.IsNullOrEmpty(command.ToolTipDescription)) && (command.ToolTipImageSource == null)))
{
return value;
}
value = new RibbonToolTip(command);
}
return value;
}
private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((myButton)d).CoerceValue(FrameworkElement.ToolTipProperty);
}
}

Related

How to restrict focus in textbox

I have a dialog with few controls. There is a TextBox named txtControl and two Buttons Accept and Cancel. I want that once the focus is in txtControl, the focus should not go away, until I click on Accept or Cancel button.
If I try to click on any other control without clicking on Accept or Cancel button, then focus should remains in txtControl. Also I don't want to disable or gray out other controls.
You might handle OnPreviewMouseDown in the root, whenever focus is on txtControl, and the mouse is not over txtControl, Accept or Cancel;
void mainWindow_previewMouseDown(object sender, MouseEventArg e)
{
if (txtControl.IsFocusWithin)
{
if (txtControl.IsMouseOver == false ||
accept.IsMouseOver ==false ||
cancel.IsMouseOver ==false)
{
e.Handle = true;
}
}
}
and you might also hadle PreviewKeyDown to see if Tab is Pressed or not.
I would create an attached property that looked for the textbox losing Keyboad focus and just force focus back in to the textbox again.
The attached property would be something like this.
public class TextBoxExtras : DependencyObject
{
public static bool GetRetainsFocus(DependencyObject obj)
{
return (bool)obj.GetValue(RetainsFocusProperty);
}
public static void SetRetainsFocus(DependencyObject obj, bool value)
{
obj.SetValue(RetainsFocusProperty, value);
}
public static readonly DependencyProperty RetainsFocusProperty =
DependencyProperty.RegisterAttached("RetainsFocus", typeof(bool), typeof(TextBoxExtras), new PropertyMetadata(false, new PropertyChangedCallback((s, e) =>
{
TextBox textBox = s as TextBox;
if (textBox != null)
{
if (!(bool)e.NewValue && (bool)e.OldValue)
textBox.LostKeyboardFocus -= textBox_LostKeyboardFocus;
if ((bool)e.NewValue)
{
textBox.LostKeyboardFocus += textBox_LostKeyboardFocus;
textBox.Unloaded += textBox_Unloaded;
}
}
})));
static void textBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null )
if (textBox.Focusable)
textBox.Focus();
}
static void textBox_Unloaded(object sender, RoutedEventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
textBox.LostKeyboardFocus -= textBox_LostKeyboardFocus;
textBox.Unloaded -= textBox_Unloaded;
}
}
}
And use it in XAML like this, the first textbox is the one that will "retain focus"
<Window x:Class="WpfApplication4.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication4"
Background="Black"
Title="MainWindow" Height="350" Width="525">
<Grid>
<TextBox local:TextBoxExtras.RetainsFocus="True" Margin="10,10,387,283"/>
<TextBox HorizontalAlignment="Left" Height="23" Margin="10,37,0,260" Width="120" />
<Button Content="Accept" HorizontalAlignment="Left" Margin="10,81,0,0" VerticalAlignment="Top" Width="75" />
</Grid>
</Window>
This kind of restriction is not a good idea.
How will your app be used by someone who can't use a mouse and uses the tab key to move between controls?
You could handle the PreviewLostKeyboardFocus at root level.
In xaml
<Window ... PreviewLostKeyboardFocus="Win_PreviewLostKeyboardFocus">
In C#
private void Win_PreviewLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
// change focus behavior only when txtControl
// is the element losing focus
if (e.OldFocus != txtControl)
return;
// if new element with focus is not Accept and is not Cancel, then disable the focus change
if (e.NewFocus != Accept && e.NewFocus != Cancel)
e.Handled = true;
}

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!

Behaviour of ItemsControl

I have a screen with several UserControls, but only one of them remains active. The other UserControls aren't shown, but the user can switch the active flag of any of those who are not active. One of the UserControl contains an ItemsControl.
I need to know all the controls in the view, including those generated by an ItemsControl, after loading the first UserControl that is active in the screen, when view is finally initialized.
For ItemsControl, wpf didn't instance any item until it was painted on the screen that contains the UserControl (so I've tried, until the Load event is launched), so that I can't found the controls contained by the view because it didn't exist.
Is there any way to change this behavior?
I try to change the value of property VirtualizingStackPanel.IsVirtualizing to false, to avoid the previous behaviour, with no success. To illustrate this, I write this view example:
<Window x:Class="ContenidoEnTabs.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">
<StackPanel x:Name="spContainer" Orientation="Vertical" VirtualizingStackPanel.IsVirtualizing="False">
<Button Content="Push" Click="Button_Click" />
</StackPanel>
</Window>
This view creates a second control not visible until the user press the button:
public partial class MainWindow : Window
{
private NotPaintedOnInitUserControl controlExtra;
public MainWindow()
{
InitializeComponent();
controlExtra = new NotPaintedOnInitUserControl();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spContainer.Children.Add(controlExtra);
}
}
The control not visible initially is as follow:
<UserControl x:Class="ContenidoEnTabs.NotPaintedOnInitUserControl"
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">
<ItemsControl ItemsSource="{Binding MyCollection}" x:Name="itemsControlTarget"
VirtualizingStackPanel.IsVirtualizing="False">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox x:Name="aTextBox" Width="80" Initialized="ATextBox_Initialized" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
and in CodeBehind I detect when the Items were created
public partial class NotPaintedOnInitUserControl : UserControl
{
public NotPaintedOnInitUserControl()
{
InitializeComponent();
DataContext = new SimpleListDataContext();
}
private void ATextBox_Initialized(object sender, EventArgs e)
{
}
}
And the DataContext used:
public class SimpleListDataContext
{
private List<string> _myCollection;
public List<string> MyCollection
{
get { return _myCollection ?? (_myCollection = new List<string> { "one", "two" }); }
set { _myCollection = value; }
}
}
Any ideas?
Thanks in advance.
If you want WPF to generate the tree for a control that isn't part of the view, you can "hydrate" and layout the control by forcing the layout to run. Something like this should work:
public partial class MainWindow : Window
{
private NotPaintedOnInitUserControl controlExtra;
public MainWindow()
{
InitializeComponent();
controlExtra = new NotPaintedOnInitUserControl();
// Force the control to render, even though it's not on the screen yet.
var size = new Size(this.Width, this.Height);
var rect = new Rect(new Point(0,0), size);
controlExtra.Measure(size);
controlExtra.Arrange(rect);
controlExtra.InvalidateVisual();
controlExtra.UpdateLayout();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
spContainer.Children.Add(controlExtra);
}
}
Not sure if this is what you're asking. If not, please clarify paragraph 2.
Have a look at LogicalTreeHelper.GetChildren(myUiElement)
This looks at the logical tree rather than the visual tree so it examines the structure without needing to have loaded the control to get the visual structure
In the below control to find is the name of the contorl i.e. myDatagrid
You could also adapt this to just get all the children of a particular control i.e.
FindChildInVisualTree(this, "mydatagrid"); // assumming this a UIElement (i.e. your in the code behind)
find the control using the below then using LogicalTreeHelper get all it's children.
public static UIElement FindChildInVisualTree(UIElement view, string controlToFind)
{
UIElement control = null;
try
{
if (view != null)
{
if ((view as FrameworkElement).Name.ToUpper() == controlToFind.ToUpper())
{
control = view;
}
else
{
DependencyObject depObj = view as DependencyObject;
if (depObj != null)
{
foreach (var item in LogicalTreeHelper.GetChildren(depObj))
{
control = FindChildInVisualTree(item as UIElement, controlToFind);
if (control != null)
{
break;
}
}
}
}
}
}
catch (Exception ex)
{
throw new ApplicationException("Error finding child control: " + controlToFind, ex);
}
return control;
}

User control with richTextBox, bindable richTextBox

I try make user control with richTextBox because I need bindable richTextbox.
I found some solution here: Richtextbox wpf binding.
I would like to use solution of Arcturus. Create user control with richTextBox control and use dependency property.
In XAML I have only richTextBox control:
<UserControl x:Class="WpfApplication2.BindableRichTextBoxControl"
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">
<Grid>
<RichTextBox Name="RichTextBox" Grid.Row="0"/>
</Grid>
</UserControl>
In CodeBehind:
public partial class BindableRichTextBoxControl : UserControl
{
public static readonly DependencyProperty DocumentProperty =
DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBoxControl),
new PropertyMetadata(OnDocumentChanged));
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (BindableRichTextBoxControl)d;
if (e.NewValue == null)
control.RichTextBox.Document=new FlowDocument();
//?
control.RichTextBox.Document = document;
}
public BindableRichTextBoxControl()
{
InitializeComponent();
}
}
I am little confuse with last line in OnDocumentChanged method.
control.RichTextBox.Document = document;
I can’t identify what is varibale document.
I think he means this:
private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
RichTextBoxControl control = (RichTextBoxControl) d;
if (e.NewValue == null)
control.RTB.Document = new FlowDocument(); //Document is not amused by null :)
else
control.RTB.Document = e.NewValue;
}
but I recommend you leave a comment on his original answer.

Clear wpf listbox selection using button in control template and no codebehind

I want to create a Style for a WPF ListBox that includes a Button in the ControlTemplate that the user can click on and it clears the ListBox selection.
I dont want to use codebehind so that this Style can be applied to any ListBox.
I have tried using EventTriggers and Storyboards and it has proved problematic as it only works first time and stopping the Storyboard sets the previous selection back.
I know I could use a user control but I want to know if it is possible to achieve this using only a Style.
It is not possible to achieve this using XAML and only the classes provided by the .NET framework. However you can still produce a reusable solution by defining a new command (call it ClearSelectionCommand) and a new attached property (call it ClearSelectionOnCommand).
Then you can incorporate those elements into your style.
Example:
public class SelectorBehavior
{
public static RoutedCommand
ClearSelectionCommand =
new RoutedCommand(
"ClearSelectionCommand",
typeof(SelectorBehavior));
public static bool GetClearSelectionOnCommand(DependencyObject obj)
{
return (bool)obj.GetValue(ClearSelectionOnCommandProperty);
}
public static void SetClearSelectionOnCommand(
DependencyObject obj,
bool value)
{
obj.SetValue(ClearSelectionOnCommandProperty, value);
}
public static readonly DependencyProperty ClearSelectionOnCommandProperty =
DependencyProperty.RegisterAttached(
"ClearSelectionOnCommand",
typeof(bool),
typeof(SelectorBehavior),
new UIPropertyMetadata(false, OnClearSelectionOnCommandChanged));
public static void OnClearSelectionOnCommandChanged(
DependencyObject d,
DependencyPropertyChangedEventArgs e)
{
Selector selector = d as Selector;
if (selector == null) return;
bool nv = (bool)e.NewValue, ov = (bool)e.OldValue;
if (nv == ov) return;
if (nv)
{
selector.CommandBindings.Add(
new CommandBinding(
ClearSelectionCommand,
ClearSelectionCommand_Executed,
ClearSelectionCommand_CanExecute));
}
else
{
var cmd = selector
.CommandBindings
.Cast<CommandBinding>()
.SingleOrDefault(x =>
x.Command == ClearSelectionCommand);
if (cmd != null)
selector.CommandBindings.Remove(cmd);
}
}
public static void ClearSelectionCommand_Executed(
object sender,
ExecutedRoutedEventArgs e)
{
Selector selector = (Selector)sender;
selector.SelectedIndex = -1;
}
public static void ClearSelectionCommand_CanExecute(
object sender,
CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
}
Example usage - XAML:
<Window x:Class="ClearSelectionBehaviorLibrary.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ClearSelectionBehaviorLibrary"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<Style x:Key="MyStyle" TargetType="Selector">
<Setter
Property="local:SelectorBehavior.ClearSelectionOnCommand"
Value="True"/>
</Style>
</Window.Resources>
<Grid>
<DockPanel>
<Button
DockPanel.Dock="Bottom"
Content="Clear"
Command="{x:Static local:SelectorBehavior.ClearSelectionCommand}"
CommandTarget="{Binding ElementName=TheListBox}"/>
<ListBox
Name="TheListBox"
ItemsSource="{Binding MyData}"
Style="{StaticResource MyStyle}"/>
</DockPanel>
</Grid>
</Window>
Example usage - Code Behind:
public partial class Window1 : Window
{
public List<string> MyData { get; set; }
public Window1()
{
MyData = new List<string>
{
"aa","bb","cc","dd","ee"
};
InitializeComponent();
DataContext = this;
}
}

Resources