I'm totally new on WPF and I need your help for creating a wpf custom ListBox with scrollbar wider than the default.
I've found a solution that works fine for a Window WPF including a ListBox:
<Window x:Class="iFixCustomControlsTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cc="clr-namespace:iFixCustomControls;assembly=iFixCustomControls"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox HorizontalAlignment="Left" Height="92" Margin="56,88,0,0" VerticalAlignment="Top" Width="357" ScrollViewer.VerticalScrollBarVisibility="Visible"/>
</Grid>
<Window.Resources>
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="100"/>
</Style>
</Window.Resources>
</Window>
This solution is not the my favorite one, because it implies to write code in a Window including a "classic" Listbox. What I need is a way to modify scrollbar inside the Listbox (if I understood fine) in Generic.xaml:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:iFixCustomControls">
<Style TargetType="local:iFixCustomListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<!--
Setting scrollbar wider than default
Something like:
<Style TargetType="ScrollBar">
<Setter Property="Width" Value="100"/>
</Style>
-->
</Style>
</ResourceDictionary>
.cs file is:
public class iFixCustomListBox : ListBox
{
static iFixCustomListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(iFixCustomListBox), new FrameworkPropertyMetadata(typeof(iFixCustomListBox)));
}
}
Is this approach correct or a better way should involve User Control instead Custom Controls?
If I understand you correctly you have a custom control type derived from ListBox and you want every instance of that control to have a wider vertical scrollbar.
If so, you can just use a custom style for your control (which you probably have already), and add a ScrollBar style to that style's Resources collection:
<Style TargetType="{x:Type local:iFixCustomListBox}">
<Style.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Width" Value="100" />
</Style>
</Style.Resources>
</Style>
I tried with this style placed in the resources collection of (a) a window, and (b) the application, and it worked fine in both cases, so I assume it would also work if placed in generic.xaml.
What about this?
<ScrollViewer Width="100">
<ListBox ...>
</ScrollViewer>
Related
I'm trying to create a custom version of UserControl to implement some standard animations for views when loading.
But when I add a ContentPresenter I'm not able to add content to my control. Why though?
Here is the Template I use for my custom control.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:EzNintendo.Desktop.Controls">
<Style TargetType="{x:Type local:AnimatedView}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AnimatedView}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
and the default code for a custom control
public class AnimatedView : Control
{
static AnimatedView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AnimatedView),
new FrameworkPropertyMetadata(typeof(AnimatedView)));
}
}
and
and that is how I try to use it.
<controls:AnimatedView x:Class="MyView"
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"
xmlns:controls="clr-namespace:MControls;assembly=MControls">
<Grid>
<TextBlock Text="Hello World!" />
</Grid>
</controls:AnimatedView>
When I remove the Grid it works just fine.
I'm wondering why setting background color of a grid in application resources results in whole window covered by grid background, even if I don't have grid panel specified in XAML main window file.
MainWindow.xaml:
<Window x:Class="TicTacToe.DesktopApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
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="Tic-tac-toe"
Height="420"
Width="420"
ResizeMode="NoResize"
WindowStyle="SingleBorderWindow">
<DockPanel>
<Button Content="Button"></Button>
</DockPanel>
</Window>
App.xaml:
<Application x:Class="TicTacToe.DesktopApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="Grid">
<Setter Property="Background" Value="Red" />
<!--Uncomment the line below to see that button seems to be hidden under the grid.-->
<!--<Setter Property="Opacity" Value="0.5" />-->
</Style>
</Application.Resources>
</Application>
MainWindow.xaml.cs and App.xaml.cs contain only auto generated code. Nothing special.
Visual Studio preview shows window as expected:
Instead of it I'm getting:
Questions
Why it behaves like that? Is there somewhere hidden and always present grid that overlays whole window and gets included by my styling rules? And if so, why it does and why it is applied with the observable delay of a fragment of a second?
That is a grid used by the Visual tree design tools to select elements in the visual tree when debugging. You can verify this using an event setter,and clicking the grid, or by running the app, not in debug mode.
<Style TargetType="Grid">
<Setter Property="Background" Value="Red" />
<EventSetter Event="PreviewMouseDown" Handler="Grid_PreviewMouseDown"/>
<!--Uncomment the line below to see that button seems to be hidden under the grid.-->
<!--<Setter Property="Opacity" Value="0.5" />-->
</Style>
,
public partial class App : Application
{
private void Grid_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
MessageBox.Show(VisualTreeHelper.GetParent(sender as Grid).ToString());
}
}
I want to bind icons to the MenuItem controls where these items are dynamically created. I tried to set the x:Shared attribute to False but always only the last item has icon.
Here is my style for the MenuItems ItemContainerStyle code:
<Window.Resources>
<Style TargetType="{x:Type MenuItem}" x:Key="MenuItemStyle" x:Shared="False">
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding IconSource}" />
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And the MenuItem definition:
<MenuItem Header="Workspaces" ItemsSource="{Binding WorkspaceItems}" Icon="{StaticResource BranchIcon}" ItemContainerStyle="{StaticResource MenuItemStyle}" />
I have already tried to set this Shared attribute on the Image control but no luck.
Any suggestion?
You are almost there!
First of all: don't be confuse by Template vs Style.
When you are setting Icon property to an Image control, only one copy is created. As a control can have only one parent, it is removed from the previous parent each time it's re-assigned.
That's why you see only one icon.
You have 2 solutions for what you want:
use datatemplate instead, and redefine the whole Template of a MenuItem
use a style with a shared image component (what you tried to achieve)
In your example the only error is that the Shared attribute should be false on the Image resource, not on the whole style. This should work:
<Window.Resources>
<Image x:Key="MenuIconImage" x:Shared="false" Source="{Binding IconSource}"/>
<Style TargetType="{x:Type MenuItem}" x:Key="MenuItemStyle" BasedOn="{StaticResource {x:Type MenuItem}}">
<Setter Property="Icon" Value="{StaticResource MenuIconImage}">
</Setter>
</Style>
</Window.Resources>
Hope it helps.
I have a ResourceDictionary that contains Style definitions for controls used within my application.
All of the styles are applied properly to the controls in the window...but the style in the ResourceDictionary for the window itself is not being applied.
This is the XAML in my ResourceDictionary that contains the style that I want to apply to my window:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- .... -->
</ResourceDictionary>
This is the XAML for the window that I am working with (trying to get this style to apply):
<Window x:Class="TryingStyles"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TryingStyles">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/StylesDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<StackPanel>
<StackPanel Orientation="Horizontal">
<Label Content="Label" Height="28" HorizontalAlignment="Left" Margin="12,12,0,0" Name="Label1" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="56,14,0,0" Name="TextBox1" VerticalAlignment="Top" Width="120" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TabControl Height="206" HorizontalAlignment="Left" Margin="12,43,0,0" Name="TabControl1" VerticalAlignment="Top" Width="250">
<TabItem Header="TabItem1" Name="TabItem1">
<Grid></Grid>
</TabItem>
</TabControl>
<GroupBox Header="GroupBox1" Margin="268,43,12,12" Width="396"></GroupBox>
</StackPanel>
</StackPanel>
</Window>
It appears that the style for the window is applied when I view the window in the IDE's "Design view" but when I run the application the style is not applied.
Does anyone know what I'm doing wrong?
It appears that there is no proper solution to your problem. TargetType in Styles doesn't manage derived types.
Here are two alternatives :
You can put a key in your style and apply the style to all your Windows.
<!-- Resource file -->
<ResourceDictionary ...>
<Style TargetType="{x:Type Window}" x:Key="WindowDefaultStyle">
<!-- .... -->
</Style>
</ResourceDictionary>
<!-- Window file -->
<Window Style="{DynamicResource ResourceKey=WindowDefaultStyle}">
Or you can use the BasedOn property of the Style.
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1">
<Style TargetType="{x:Type Window}" x:Key="BaseStyle">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- Inherit from the BaseStyle and define for the MainWindow class -->
<Style TargetType="{x:Type my:MainWindow}" BasedOn="{StaticResource ResourceKey=BaseStyle}" />
</ResourceDictionary>
It's very strange that it works with the designer but not when the application runs.
The problem seems to be the TargetType of your Style. Wpf seems not be able to match the Window class with your derivated class TryingStyles.
Change your TargetType and it will work :
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:primatives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WpfApplication1">
<Style TargetType="{x:Type my:TryingStyles}">
<Setter Property="Background" Value="#FF121212"></Setter>
<Setter Property="Height" Value="768"></Setter>
<Setter Property="Width" Value="1024"></Setter>
</Style>
<!-- .... -->
</ResourceDictionary>
I'm quite late to the party here, but I found a solution to have Style TargetType="{x:Type Window}" apply to every window application-wide, as one would expect. For the record, the reason this doesn't work is because each window you create is not a Window but a new type that derives from window (e.g. "MainWindow"), and Style's TargetType doesn't apply to derived classes. Anyway:
First, ensure your App.xaml has a Startup property defined; so inside the <Application> tag you'd add Startup="Application_Startup" or whatever you want to call the startup method.
Then, inside App.xaml.cs add:
private void Application_Startup(object sender, StartupEventArgs e)
{
FrameworkElement.StyleProperty.OverrideMetadata(typeof(Window), new FrameworkPropertyMetadata
{
DefaultValue = Application.Current.FindResource(typeof(Window))
});
}
where the method name matches whatever you listed as the Startup property in App.xaml. And of course, if you already have an existing startup method being run, just add the code contained within to that.
This basically just fixes it so that keyless Styles targeting "Window" will apply their changes to every window in your application, as you probably expected would occur without this code snippet. (That is of course assuming your style is already scoped application-wide, for example by containing it within a ResourceDictionary that is merged into App.xaml.)
I've got a UserControl that contains a button:
<Button Content="Button"/>
And a style:
<Style TargetType="Button">
<Setter Property="Background" Value="Blue"/>
</Style>
The parent window (or another UserControl) may set another more general style:
<Style TargetType="Button">
<Setter Property="Background" Value="Red"/>
</Style>
The result is (what is obvious) that parent buttons will have more general style (Red) and my user control will have buttons with more specific style (Blue).
I'm wondering how to invert such behaviour in order to achieve something like setting the default style in my custom user control which could be then overriden in parent control or window if necessary?
The key is, that default style is defined first in custom user control and it is overriden automaticly by its parent. That is way I called it an inversion.
The imaginary example of the solution maight look like the following:
<Style TargetType="Button" StylePriority="Default">
<Setter Property="Background" Value="Blue"/>
</Style>
The StylePriority could indicate that if there is no other style defined for that button, then the default style should be applied to it.
You could use dynamic resources.
A UserControl:
<UserControl x:Class="Example.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example">
<UserControl.Resources>
<Style TargetType="local:UserControl1">
<Style.Resources>
<Style TargetType="Button" x:Key="UserControl1.DefaultButtonStyle">
<Setter Property="Background" Value="Red"/>
</Style>
</Style.Resources>
</Style>
</UserControl.Resources>
<Button Content="UserControlButton" Style="{DynamicResource UserControl1.DefaultButtonStyle}"/>
</UserControl>
And a Window:
<Window x:Class="Example.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Example">
<Window.Resources>
<Style TargetType="Button">
<Setter Property="Background" Value="Blue" />
</Style>
</Window.Resources>
<StackPanel>
<local:UserControl1 >
<local:UserControl1.Resources>
<Style x:Key="UserControl1.DefaultButtonStyle" TargetType="Button"
BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="FontSize" Value="40" />
</Style>
</local:UserControl1.Resources>
</local:UserControl1>
<Button Content="WindowButton" />
</StackPanel>
</Window>
If you remove the style for the control in the window, the default user control button style will be applied.
Create a dependency property in your UserControl for the buttons colour, and then bind to it. You can specify a default value of blue for that property.
public static readonly DependencyProperty ButtonColorProperty =
DependencyProperty.Register("ButtonColor", typeof(Color), typeof(MyUserControl),
new PropertyMetadata(Colors.Blue));
public Color State
{
get { return (Color)this.GetValue(ButtonColorProperty); }
set { this.SetValue(ButtonColorProperty, value); }
}
<UserControl ...
x:Name="root">
<Button Content="Button" Background="{Binding ElementName=root, Path=ButtonColor}" />
</UserControl>
Then set that property to red where you want to use the UserControl.
<local:MyUserControl ButtonColor="Red" />