Set property after command - wpf

I have a StatusBar below the screen in SL4 (using PRISM), just a very simple Telerik RadDockPanel.
I also have a menu (Telerik RibbonView with RadRibbonGroup and RadRibbonToggleButton). When the toggle button is pressed, I want to set the text to 'ON' and 'OFF', and I want to hide the status bar, but... only in XAML (not using code behind).
I believe this is a common SL/WPF coding practice... but how ?

Have to use EventTrigger (check example bellow on page by link that I provided) and ObjectAnimationUsingKeyFrames to change properties that aren't animated (Text, Visibility so on).
Check good example in other answer on so.

You can specify a DataTrigger in your window like this -
<StatusBar.Style>
<Style>
<Style.Triggers>
<DataTrigger
Binding="{Binding ElementName=MyRadRibbonToggleButton, Path=IsChecked}"
Value="True">
<Setter Property="Grid.Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</StatusBar.Style>
In case you can't use ElementName binding then you can use a property in your ViewModel(corresponding to RadRibbonToggleButton state). Similar Trigger can be created for a TextBlock/Label to show On/Off text.
This is how I implement this kind of functionality in WPF/MVVM applications;
You may have to apply some hack to make this work with telerik controls.

Related

Let one control be enabled/disabled based on another control

I have two DataGrid's that I want do have enabled/disabled based on whether precisely 1 element is selected in another DataGrid. What is the simplest way to accomplish this dependency control in WPF?
You could use a trigger:
<DataGrid.Style>
<Style TargetType="DataGrid">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedItems.Count,
ElementName=datagrid1}"
Value="1">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
You could:
Create an IValueConverter, perhaps it is called NotEqualToOneBooleanConverter
Bind IsEnabled from one DataGrid to the SelectedItems.Count on the other
Set the Converter on this Binding to be the NotEqualToOneBooleanConverter
This approach is nice since once your converter is created, it can be applied throughout your XAML and to any type and any property (not just DataGrid or SelectedItems.Count). To make it even more flexible, you could have a more generic version of this converter that could compare any two values specified directly from XAML (one from the Binding and one specified as property on the Converter).
The downside to this approach - it's XAML only, and difficult to test especially if what you are trying to achieve is a business requirement and not just a graphical effect.
Hope this helps!
This is my quick hack:
tablesControl.SelectionChanged += (sender, sce) =>
{
var c = tablesControl.SelectedItems.Count;
var orderingPossible = c == 1;
itemsControl.IsEnabled = orderingPossible;
};
In the first Grid have an event or Command that is fired when you click on that cell, in this event you need to have some bool property you can set to false, then bind the Enabled property to this bool. If you are using MVVM this will be very easy, have a look at this to see how - http://www.youtube.com/watch?v=tKfpvs7ZIyo

How to get TreeViewItems to not inherit Tooltip property from their parent

I have an application in which is a quasi IDE where a TreeView is acting as a solution explorer. What the user is designer is a screen layout which could look like this.
Root
Menus
MainMenu
MenuItem1
Button Bars
MainBar
Button1
I originally had issues with context menus. In the example above MenuItem1 doesn't have a context menu but MainMenu does. Well, MenuItem1 would inherit the context menu from MainMenu. I got by this by creating an empty context menu and assigning it to MenuItem1. I'd like something more elegant though.
I have the same issues with tooltips. If I assign one to MainMenu then MenuItem1 inherits the one assigned to MainMenu. I tried setting the MenuItem1 tooltip to null, did nothing. If I set it to "", an empty string it overrides the MainMenu tooltip but when you hover over MenuItem1 a small empty tooltip box appears. I thought the system would have been smart enough to not show the box if it was an empty string but apparently not.
How can I prevent children from inheriting context menu and tooltip properties from their parents?
Updated
Still having issues with this. I analyzed my items using Snoop and it indicates that these properties are inheirited, but I still don't see any solution to breaking the inheritance.
The only kludge I can think of is that for every tooltip to handle the ToolTipOpening event and inspect the string, if it has no length then jsut close it immediately. There must be a better way though.
I ran into the exact same problem but I found a solution that works for me. I changed the visibility of the tooltip so that it no longer appears for empty strings.
System.Windows.Controls.ToolTip tt = new System.Windows.Controls.ToolTip();
tt.Content = tooltipDescription;
if (tooltipDescription == null)
tt.Visibility = Visibility.Collapsed;
item.ToolTip = tt;
Have you tried setting ToolTipService.IsEnabled="False" this will disable your Tooltip on the desired element.
For myself, I created a style with zero Width and Height:
<Style x:Key="NullToolTip" TargetType="{x:Type ToolTip}">
<Setter Property="Width" Value="0" />
<Setter Property="Height" Value="0" />
<Setter Property="Content" Value="{x:Null}" />
</Style>
When I created ToolTip with this style and placed in resources:
<ToolTip x:Key="NoToolTip" Style="{StaticResource NullToolTip}" />
Then set this ToolTip for each item:
<TreeViewItem Header="Sample" ToolTipService.ToolTip="{StaticResource NoToolTip}">
or in style:
<Setter Property="ToolTipService.ToolTip" Value="{StaticResource NoToolTip}" />
In this case, null ToolTip for item will be default, but when you set our ToolTip, it will be defined only for him.
Firstly masking a tooltip should be done with null and not string.empty. Secondly if you had used hierarchical data template and itemssource binding for your treeview then you could have set tooltips based on your template hierachy (such as bound to a property in your object hierarchy from model or itemssource) in which case they must had taken an effect based on your specific treeview item.
As of now you can use null to mask.
The other answers here all had issues for me so here's the approach I came up with which does avoid child tree items showing the parent item's tip.
Similar to some other answers, I use a style with a setter for the Tooltip property. The key differences are:
Binding the Visibility of a ToolTip element instead of the TextBlock element showing the tip.
Wrapping the TextBlock with a Border element. This avoided occasionally seeing a tiny, empty tip block.
<local:StringToVisibilityConverter x:Key="strToVisibilityConverter"/>
<Style x:Key="MyTreeStyleKey" TargetType="TreeViewItem">
<Setter Property="ToolTip">
<Setter.Value>
<ToolTip Visibility="{Binding TipText, Converter={StaticResource strToVisibilityConverter}}">
<Border>
<TextBlock Text="{Binding TipText}"/>
</Border>
</ToolTip>
</Setter.Value>
</Setter>
</Style>
StringToVisibilityConverter is a simple converter I created which returns Visibility.Collapsed for null or emptry strings, Visibility.Visible otherwise.
<[YourControl].Resources>
<Style TargetType="ToolTip" x:Key="InvisibleToolTip">
<Setter Property="Visibility"
Value="Collapsed" />
</Style>
</[YourControl].Resources>
<[YourControl].ToolTip>
<ToolTip Style="{StaticResource InvisibleToolTip}"/>
</[YourControl].ToolTip>

WPF button styling depending on active view

I'm using Caliburn Micro to develop a simple MVVM WPF application.
My ShellView has a single ContentControl and three buttons each which bind to a public method in my ShellViewModel, lets say ActivateView1, ActivateView2 and ActivateView3.
My ShellViewModel inherits from Conductor and each Activate method calls ActivateItem(new View1ViewModel()), etc.
So far so good. When I click a button, a new view gets activated in the ContentControl. The problem is that I need each button to change style when its "associated view" is active and I have really no idea how to achieve this functionality. Do you have any suggestions?
I'm fairly new to Caliburn Micro and WPF-styling so any help will be much appreciated.
I am not very sure about this but still I can think of something like this,
you can create a style and add the style to your button. something like this
<Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="IsPressed" Value="True">
<Setter Property="Fill" TargetName="yourButtonName" Value="Black"/>
<Setter Property="Margin" TargetName="yourButtonName" Value="5,0,5,0"/>
</Trigger>
</Style.Triggers>
</Style>
and you can add this style to your button.
I can think of two possible options you could use:
You could bind your buttons style properties to properties on you ShellViewModel. In those properties you can determine the style to return based on the shells Active view i.e.
return ActiveItem == button1ViewModel ?
(Style) App.Current.Resources["Button1ActiveStyleKey"] :
(Style) App.Current.Resources["Button1InactiveStyleKey"];
this would mean your ViewModel would be aware of Styles which you may not want. If that is the case option two would be to write a Caliburn.Micro IResult which changes the style of the button and return 3 of those (one for each button) from a Coroutine that is invoked via the button click i.e.
public IEnumerable<IResult> ButtonOneClicked()
{
yield return new ChangeButtonStyle("Button1Name", "Button1ActiveStyleKey");
yield return new ChangeButtonStyle("Button2Name", "Button2InactiveStyleKey");
yield return new ChangeButtonStyle("Button3Name", "Button3InactiveStyleKey");
}
The implementation of the ChangeButtonStyle IResult would search the view (provided via the ActionExecutionContext parameter to IResult.Execute) for a control with the name provided to the 1st parameter of ChangeButtonStyle ctor, and then set the style property of that control using the resource key provided as the 2nd paramter to the ChangeButtonStyle ctor.
You can use
<Trigger Property ="IsPressed" Value ="True">
I think it does the trick...

How to disable button when its Button.CommandProperty is null

Short explanation
Button.CommandProperty is bound to SomeObject.SomeCommand property of the ViewModel. When SomeCommand property of SomeObject is set to null or entire SomeObject property is set to null, this button remains enabled. How can the button be disabled under this circumstances?
Detailed explanation
I am creating application using MVVM, which behaves like a browser:
Main view_model (which corresponds to main window as view) has a list of Workspace view_models. Each Workspace view_model corresponds to TabPage in windows's TabControl.
Main view_model has CurrentWorkspace property which corresponds currently active TabPage.
In main window where is a toolbar with buttons, which utilizes commands provided by the CurrentWorkspace. For example, access to reloading workspace data is realized as:
<Button Name="btReload" Content="Reload"
Command="{Binding Path=CurrentWorkspace.ReloadCommand, UpdateSourceTrigger=PropertyChanged}"/>
I tried to accomplish the task of button disabling by creating DataTriggers, but it seems that triggers works only first time and no more:
<Button Name="btReload" Content="Reload"
Command="{Binding Path=CurrentWorkspace.ReloadCommand, UpdateSourceTrigger=PropertyChanged}">
<Button.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=CurrentWorkspace, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="{x:Null}">
<Setter Property="dxb:BarButtonItem.IsEnabled" Value="False"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=CurrentPage.CurrentWorkspace, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Value="{x:Null}">
<Setter Property="dxb:BarButtonItem.IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
it looks really stupid: like MS Word with documentless client area and at the same time with a lot of ready-for-click buttons in toolbar (with formatting and other document-specific features). Please, help me, :)
P.S. When adding to toolbar a button with DataContext binded to CurrentWorkspace, then its DataContextChanged event fires properly when activating or adding or removing workspace tab in the window. So, the problem somewhere in DataTrigger (or in View as generally), not in it's ViewModel(s).
UPDATE
I uploaded sample project on VS2010, link for the archive: http://www.filefactory.com/file/b43455e/n/WhatIfCommandIsNull.rar
bellow its description.
TextBox is bound to the ViewModel.Data property
Assigning or removing ViewModel into/from Window.DataContext can be done by clicking two buttons - btAssignViewModel and btRemoveViewModel respectively
ViewModel exposes two commands, one of which sets ViewModel.Data to string value, other - sets it to the NULL
These commands are bound to the buttons btSetData & btResetData via their Button.Command properties
As you can see, when Window.DataContext is set to the ViewModel instance, both the commands working properly, & ResetDataCommand.CanExecute is working too (when ViewModel.Data is NULL, ResetDataCommand.CanExecute returns false & button btResetData is disabled). Once the Window.DataContext is set to null, last two buttons enables (for the first two ones trere are no commands are bound).
The problem is to realize declaratively (via triggers) next four rules:
If btAssignViewModel.DataContext is not null then btAssignViewModel.IsEnabled = false, else true.
If btRemoveViewModel.DataContext is null then btRemoveViewModel.IsEnabled = false, else true.
If ViewModel.Data is null then btSetData.IsEnabled = true, else false.
If ViewModel.Data is null then btResetData.IsEnabled = false, else true.
I think that first two rules can be realized using Triggers, second two - using DataTriggers. But they aren't working, so I erased them from the project.
This might work (pending your circumstances)
<Button.Style>
<Style TargetType="{x:Type Button}">
<Style.Triggers>
<Trigger Property="Command" Value="{x:Null}">
<Setter Property="IsEnabled" Value="false"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>

Proper way to display a view using MVVM

I am brand new to both wpf and MVVM. I have a Mainwindow that has two views left side has a usercontrol with a listbox and the list box has a edit button inside of it. On the right I have another view that contains all my controls for viewing and editing the record. I can select an item in the list box and edit my record since using binding it automatically populates by the selectedItem object. What I want to do is when the user hits the edit button show the view on the right if they hit another button contained in the list box then show that view on the right and close the previous view. I think I am missing a big concept here since most of the examples are to simplistic and just show one view. I really dont want to have to do it in the code behind. I have looked at John smiths tab and would like to do something similur without the tabs though. Any help would be greatly appreciated.
It sounds like both views need to share the same context (ie ViewModel) then they will stay in synch automaticall by the magic of dependency properties...
I would probably try setting it up so that clicking either button (View or Edit) sets the DataContext of the right frame. The RightFrame View gets displayed using DataTemplates based on the DataContext.
So your xaml would be something like this:
<DataTemplate DataType={x:Type MyEditingViewModel}>
<!-- Editing Object View -->
</DataTemplate>
<DataTemplate DataType={x:Type MyViewingViewModel}>
<!-- Viewing Object View -->
</DataTemplate>
and your button click events would be something like this:
private void EditButton_Click(object sender, EventArgs e)
{
RightFrame.DataContext = new MyEditingViewModel((sender as Button).DataContext)
}
private void ViewButton_Click(object sender, EventArgs e)
{
RightFrame.DataContext = new MyViewingViewModel((sender as Button).DataContext)
}
So basically, what you're trying to do is have your view model decide which view it should be presented in, and make that decision in response to user choice.
How I do this sort of thing:
My view model exposes a view style property, which is an enumerable. In the view for the view model (usually a user control), I implement a DockPanel to contain each style of view. Each DockPanel is assigned a style, and the styles are defined like this:
<Style x:Key="Style_View1" TargetType="DockPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ViewStyle}" Value="View1">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style x:Key="Style_View2" TargetType="DockPanel">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ViewStyle}" Value="View2">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
(Obviously you don't need to use a DockPanel if a Grid or StackPanel is more appropriate for your scenario. And you can implement a different user control for each style of view if you want to keep your code nicely segmented.)
So as long as the value of ViewStyle is one that there's a corresponding style for, that view style will be visible. Since all of the styles set Visibility to Collapsed by default, there will only ever be at most one view style visible.
There are lots of ways of selecting the view style - create a command for each one and bind it to buttons, create a group of radio buttons and use a value converter, set the view style in response to other properties in the view model - whatever works.

Resources