I want to initiate a bound command, but I don't want to use a Button on my UserControl. In effect the UserControl is itself a Button. When it is clicked anywhere on its surface I want to initiate a bound command. Is there a way to give a UserControl a command?
In a side note: one command for one control and only a few certain out-of-the-box controls? This all seems a little clunky. I'm starting to think that MVVM is impractical. I can decouple my UI just fine with Interfaces and OOP. Anyway, I still have hope.
Also, I'm not willing to hack anything or use an expensive workaround. If I can't do this, I'm abandoning MVVM.
Take a look at the ICommandSource interface here: http://msdn.microsoft.com/en-us/library/system.windows.input.icommandsource.aspx. If you want a control to have a command, then your control should implement this interface. Examples of controls that implement this interface are ButtonBase and MenuItem. Hope this helps.
If your UserControl is essentially a Button, why are you writing your own UserControl instead of using the Button class?
To add more info, here's what you do:
Subclass Button, put any extra DependencyProperties that you need in there - it should be a very empty class (you could even have something like public class MyCoolButton : Button { }
Add a Style whose TargetType is MyCoolButton - don't name the style so it applies to all MyCoolButtons
Override the default Template of the style, then paste in your Xaml code. You might have to do some work here to handle the "Normal / Pushed / Disabled" states. If you're using v4.0, you can use VSM here.
I will agree with Paul Betts.
Quite often I create my own ListBoxItemContainerStyle using a button as the top container with nothing but a propertyless content presenter in it. This allows me to use the buttons functionality (like Command) without having the Windows chrome on it.
Putting it in the ListBoxItemContainerStyle also lets me make it so that when it is clicked it does not display the normal dotted border (FocusVisualStyle={x:Null}).
Are you using Visual Studio or Expression Blend to do your styling?
Additionally, some MVVM frameworks provide an interface for adding a command-ish ability to controls other than buttons. Caliburn has a pretty rich command pattern. I am not sure if it allows binding commands on non-button controls, however.
The OP asked for an example of how you could use a button control, but with the content properly filling the entire button. You can do this using the ContentAlignment properties:
<Button HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<Button.Content>
<Grid IsHitTestVisible="False">
<Grid.RowDefinitions>
<RowDefinition Height="30" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Row0" />
<TextBlock Grid.Row="1" Text="Row1" />
</Grid>
</Button.Content>
</Button>
This creates a button with two labels spaced using a Grid control. I mark the Grid to turn off HitTestVisible, as you have to decide which controls should interact like the button and which should interact like controls. For instance, you might have an embedded TextBox that you want to be clickable without clicking the button, in which case it should have HitTestVisible=True.
WPF supports layers and transparency :
Panel.ZIndex
You can create anything that supports commanding on a superior transparent layer, the size you want, to act as a button.
Related
I'm using an MVVM pattern for my WPF application. If the "home" view model, which controls the layout of my application's main window, I have a ChildViewModel property. This holds a viewmodel that can be switched according to what the user is doing. When they select menu items, the child view model switches and the main area of the screen (it's in an Outlook style) switches accordingly.
I do this with a ContentControl and DataTemplate like this: (I'm only showing one of the embeddable views here to keep it short).
<ContentControl Grid.Row="1" Grid.Column="1" Margin="3"
Content="{Binding ChildViewModel}">
<ContentControl.Resources>
<DataTemplate DataType="{x:Type vm:VersionsViewModel}">
<Embeddable:VersionsView />
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
I also want to add a ribbon to my main window, using the Telerik RadRibbonView control. I want this to have some fixed tabs and buttons that are always visible. In addition, I want to add and remove entire tabs, and buttons within existing tabs, according to the type of child view model. I'd like this to be done in the view in a similar manner to the way I've done the content control, above.
Is this possible? I've tried lots of things but got nowhere so far. I know I could do it by creating a huge "super ribbon" and binding visibility properties but this seems cludgey. I could also have multiple ribbons, each containing the common controls, but this would cause a maintenance problem.
In the end I went with the "super ribbon" approach, as I couldn't find any other way.
I'm using a control template to show validation errors on each of my controls using the built-in WPF's validation mechanism, and everything works fine. The controlTemplate looks like this:
<ControlTemplate x:Key="MyErrorTemplate" TargetType="{x:Type Control}">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="Red" BorderThickness="2" CornerRadius="3">
<AdornedElementPlaceholder Name="MyAdorner" />
</Border>
<Image Name="imgError"
Source="/MyAssembly;component/Images/ValidationIcon.png"
ToolTip="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
</StackPanel>
</ControlTemplate>
I have read that the validation mechanism wraps the validated control up with the control template (the default one or a custom one like above) whenever the control gets an error.
"When the WPF validation system detects an invalid control it creates
and adorner that holds a control (...), inserts a control into it and sets that control
template to the content of the Validation.ErrorTemplate attached
property.
It positions the adorner above the original control so that the
AdornedElementPlaceholder is exactly above the control and that let us
easily place the control template content relative to the original
control" (see more)
How can I perform this same behavior for another functionality? I mean use "MyErrorTemplate" without the WPF's validation system, is it possible?
so if I understand you correctly you want to have the same validation adorning thing without WPF's validation, right?
The approach then is actually to rebuild the components of WPF's validation system:
create a Dependency Property MyCustomErrorTemplate to hook up your template to the control
create a Dependency Property HasCustomError to enable showing the error
within MyCustomErrorTemplate_Changed hook up to the HasCustomError_Changed to enable showing/hiding of your adorner
create/copy the TemplatedAdorner Class that is then showing your Template
I recommend you use .NET Reflector or ILSpy to look at the following code to get some understanding of what's going on. This isn't actually very complex or hard to understand:
in PresentationFramework.dll:
System.Windows.Controls.Validation (especially the private static void ShowValidationAdornerHelper(DependencyObject targetElement, DependencyObject adornerSite, bool show, bool tryAgain)
MS.Internal.Controls.TemplatedAdorner (sadly this is internal, so you either have to copy it or use some Reflection on it)
Why not? You can have similar attached properties MyValidation.Errors and HasErrors and fill them with your custom logic. And you can have trigger that replaces ControlTemplate with ErrorTemplate when HasError is true. I think this simple approach will do that you need although i am not quite sure that i exactly understand that you need.
I want to change Button drawing based on button size using XAML.
I know it is possible using c# code not sure about XAML
Thanks
Update :
my code is like
<Grid Width="60" Height="60">
<Ellipse Width="57" Height="57" StrockThickness="1">
</Ellipse>
</Grid>
I am applying above style to Button control. but here Width/Height is hard coded. I want it dynamically design time. so when I increase/decrease button size ellipse become accordingly
Thanks again
You should be able to use Property or Event triggers (in XAML). This is probably the preferred way to do this kind of behaviour as it puts the User Experience completely in the designers hands (via XAML) rather than hooking up event handlers (in C# code) that a developer now needs to maintain in order to modify the user experience.
I don't have quick access to VS to test this out right now, but I can try tomorrow if there is no answer by then.
I'm using the Cinch MVVM framework, however I think this is something that relates to all WPF approaches.
I want to have a primary screen - Shell or MainWindow - which then contains various viewmodels. To navigate between viewmodels I'm using (or going to use) a tab control styled as a button strip with the content area beneath - which is all ok as I add the viewmodels to the tabcontrol (well to the 'Views' collection which is bound to the tab control) at runtime.
A screen that doesn't fit into this methodology is the sign in screen, which I don't really want to add to the tab control - preferably it should be in it's own usercontrol which takes up the entire screen apart from covering the logo; that is, I would like it to appear in the same window rather than a popup dialog, however I'm not sure how to add/ remove controls dynamically and then add subsequent tabcontrol once the user has signed in successfully (and remove the sign in screen). What containers should be used?
TIA.
The easiest way is put your tabcontrol in a Grid without columns and rows so it fill the grid by default. Then add an extra grid or loginusercontrol to the grid as shown below. The moment a user needs to login you can set the visibility of the MainTabControl" to collapsed and of the LoginGrid to Visible and switch it back after a succesfull login. I hope that the xaml below will help you enough.
<Grid>
<TabControl x:Name="MainTabControl" Visiblity="Visible">
... put your tabs here ...
</TabControl>
<Grid x:Name="LoginGrid" Background="#60FFFFFF" Visibility="Collapsed">
... put your usercontrol to login here or the login controls themself
</Grid>
</Grid>
You could use a ContentControl with content bound to a view model. So you'd have two view-models representing the sign-in screen and the main screen and use DataTemplate to display appropriate screen.
<Window.Resources>
...
<DataTemplate DataType="{x:Type my_view_models:SignInViewModel}">
<my_controls:SignInScreenView />
</DataTemplate>
...
</Window.Resources>
<ContentControl Content={Binding} />
You may be interested by Lakana, it is a lightweight and non intrusive navigation framework for WPF.
Riana
What I'd like is a control that functions just like the tab control but instead of having the tabs along the top, the items would be displayed in a list box along the side. I imagine it's possible but haven't found any examples, I'm hoping there's someone here that's done something like this.
WPF controls are designed to enable exactly what you want. To reuse control functionality while completely replacing the visual representation. You will have to create your own ControlTemplate for the TabControl. You can find a TabControl ControlTemplate Example on MSDN. You will also have to study the Control Authoring Overview on MSDN.
I actually find the Silverlight 3 documentation somewhat easier to digest, and even though there are some differences when it comes to control styling the fundamental concepts are still the same. You can read Customizing the Appearance of an Existing Control by Using a ControlTemplate on MSDN to learn about control templates and then study TabControl Styles and Templates to discover what is required to create you own control template in Silverlight.
You can use Expression Blend to extract the the default TabControl template in WPF.
You don't need to use a TabControl at all. You could just bind your ListBox to a list of items, and put a ContentControl beside it, bound to the selected item :
<DockPanel>
<ListBox Name="listBox"
DockPanel.Dock="Left"
ItemsSource="{Binding Items}"
DisplayMemberPath="Name"/>
<ContentControl Content="{Binding SelectedItem, ElementName=listBox}"
ContentTemplate="{StaticResource theTemplate}"/>
</DockPanel>