I am currently fighting against another WPF struggle, namely mouse events.
I basically have a very simple control (a Border containing a Grid which itself has a few TextBlocks). I am trying to achieve a simple behavior: Double click should turn the control into edit mode (which in fact hides the TextBlocks with TextBoxes bound to the same data.
Nothing fancy, right? Well still, I'm struggling. The MouseDoubleClick linked to my UserControl just fires when I click in a control (like, clicking ON a TextBlock). If I click on an empty space between TextBlocks, nothing is fired. Not even MouseDown.
How could I make it work so as to catch every mouse click? I assumed that linking a MouseDown event to a Border should catch every click on the border but... it ended up not catching clicks on empty parts of the border.
Here is some draft code I made for you to run it:
XAML:
<StackPanel Orientation="Vertical">
<Border Height="400" Width="400" HorizontalAlignment="Center" VerticalAlignment="Center" BorderBrush="Black" BorderThickness="2"
MouseDown="Border_MouseDown" MouseUp="Border_mouseUp">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Text="BLUFF" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="1" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="1" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="2" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<TextBlock Text="BLUFF" Grid.Column="2" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
<TextBlock Height="100" Width="300" HorizontalAlignment="Center" TextAlignment="Center" x:Name="thetext" Visibility="Collapsed"
Foreground="White" Background="Red" Text="CLICKED!" />
</StackPanel>
Code behind:
private void Border_MouseDown(object sender, MouseButtonEventArgs e)
{
thetext.Visibility = Visibility.Visible;
}
private void Border_mouseUp(object sender, MouseButtonEventArgs e)
{
thetext.Visibility = Visibility.Collapsed;
}
Now try to click one of the "BLUFF" texts: A "CLICKED" Text will appear. Try clicking somewhere else, between the TextBlocks: Nothing happens.
Thank you!
<StackPanel Background="Transparent" ... >
or
<Border Background="Transparent" ... >
should do the trick...
This makes the grid transparent, however visible for mouse-clicks.
Look here form more Information.
There are some other circumstances, where you have to use the PreviewXXX- event, this is when a child element "swallows" the event away, but in your case, the above should be what you're looking for.
Related
In my wpf application, I have a Usercontrol in a wpf window which is a part of another module.This parent Usercontrol is having another two child user controls in it. These two child usercontrol is loading data from two different CSV files and shows graphs on each usercontrol. When the main window loads, these two usercontrols loads data from these 2 csv files and display the graphs. But the problem is, this process is taking too much time and the window will become non responsive.
I want to have a loading adorner (like loading....please wait) on the screen and the UI will be responsive. When the 2 usercontrols loaded the graphs properly, the Loading adorner will be gone. Could any one please share the code for this ??
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center" Height="30" Width="Auto">
<TextBlock Text="Your Name " FontFamily="Verdana" Margin="5" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="12" FontWeight="Bold" />
<ComboBox Name="cboName" ItemsSource="{Binding GraphStringType}" Height="25" Width="300" HorizontalAlignment="Center" VerticalAlignment="Center" Focusable="False"
IsTextSearchEnabled="True" StaysOpenOnEdit="True" IsReadOnly="True" IsEditable="True" Text="-- Select your Name --">
<ComboBox.ItemTemplate>
<DataTemplate>
<CheckBox Width="100" Height="23" Content="{Binding}" IsChecked="{Binding IsChecked}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<Grid Name="graphGrid" Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<useCtrl:UsrCtrlGraphUI x:Name="graph1" GraphFilePath="{Binding FileNameWithPath}" Grid.Column="0" Height="Auto" Width="Auto" />
<GridSplitter HorizontalAlignment="Stretch" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext"
VerticalAlignment="Stretch" Grid.Column="1" Grid.Row="1" Width="5" Background="Silver">
</GridSplitter>
<useCtrl:UsrCtrlGraphUI x:Name="graph2" GraphFilePath="{Binding FileNameWithPath}" Grid.Row="1" Grid.Column="2" Height="Auto" Width="Auto" />
</Grid>
The loading data from the 2 csv files is a very huge task and it causes non responsive UI.
How to set a loading adorner over the window and the UI becomes responsive ?
I'm learning how to use gridsplitters and I'm getting confused by how seemingly different a horizontal splitter is to a vertical one. If you look at the XAML below, the first gridsplitter I made very easily, everything worked as expected, I set what row and column it should be in, then set how many rows it should span. It placed the splitter where I would expect it, on the right side on the column. (It doesn't actually resize anything and I don't know why, but at least it's there, where it's supposed to be).
The second splitter however will simply not cooperate in any way. I want it to be placed above the textbox at the bottom of the form. So I set it to that one cell, and it looks like it put itself in the center of the row. I'm obviously getting confused by something simple I don't understand, could someone tell me why the second gridsplitter is not behaving like I want?
<Window x:Class="FontViewer.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"
xmlns:local="clr-namespace:FontViewer"
mc:Ignorable="d"
Title="Font Viewer" Height="480" Width="600">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.8*"/>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.7*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="0.3*"/>
</Grid.RowDefinitions>
<Border CornerRadius="6"
BorderThickness="1"
BorderBrush="Gray"
Background="LightGray"
Padding="8"
Margin="6"
Grid.ColumnSpan="2">
<TextBlock FontSize="14"
TextWrapping="Wrap">
Select a font to view from the list below.
You can change the text by typing in the region at the bottom.
</TextBlock>
</Border>
<ListBox x:Name="FontList"
Grid.Row="1"
Grid.RowSpan="5"
HorizontalAlignment="Right"
ItemsSource="{x:Static Fonts.SystemFontFamilies}"
Width="190"
Margin="0 0 0 8">
</ListBox>
<TextBox x:Name="SampleText"
Grid.Row="5"
Grid.Column="1"
VerticalAlignment="Center"
Height="18"
MinLines="4"
Margin="0 0 6 0"
TextWrapping="Wrap"
ToolTip="Type here to change the preview text.">
The quick brown fox jumps over the lazy dog.
</TextBox>
<TextBlock Text="{Binding ElementName=SampleText, Path=Text}"
FontFamily="{Binding ElementName=FontList,Path=SelectedItem}"
FontSize="10"
TextWrapping="Wrap"
Margin="6"
Grid.Column="1"
Grid.Row="1"/>
<TextBlock Text="{Binding ElementName=SampleText, Path=Text}"
FontFamily="{Binding ElementName=FontList,Path=SelectedItem}"
FontSize="16"
TextWrapping="Wrap"
Margin="6"
Grid.Column="1"
Grid.Row="2"/>
<TextBlock Text="{Binding ElementName=SampleText, Path=Text}"
FontFamily="{Binding ElementName=FontList,Path=SelectedItem}"
FontSize="24"
TextWrapping="Wrap"
Margin="6"
Grid.Column="1"
Grid.Row="3"/>
<TextBlock Text="{Binding ElementName=SampleText, Path=Text}"
FontFamily="{Binding ElementName=FontList,Path=SelectedItem}"
FontSize="32"
TextWrapping="Wrap"
Grid.Column="1"
Grid.Row="3"
Margin="6,84,6,5.765" Grid.RowSpan="2"/>
<GridSplitter Grid.Row="0"
Grid.Column="0"
Grid.RowSpan="6"
Width="3"
Background="LightGray"
ResizeBehavior="PreviousAndNext"
ResizeDirection="Columns" />
<GridSplitter Grid.Row="5"
Grid.Column="1"
Height="3"
Background="Black"
ResizeBehavior="PreviousAndNext"
ResizeDirection="Rows" />
</Grid>
Edit: It looks like I didn't include the closing window tag in the code, but it is there, it just gets omitted for some reason.
You have
Grid.RowSpan="6"
On the first one, which will stretch it.
Try taking it out temporarily.
It is usual to set stretch on a gridsplitter.
Change your other one to:
<GridSplitter Grid.Row="5"
Grid.Column="1"
Height="3"
Background="Green"
ResizeBehavior="PreviousAndNext"
HorizontalAlignment="Stretch"
ResizeDirection="Rows" />
And it will stretch horizontally.
Still won't do much, but it will stretch horizontally.
Dificult to tell what else you want this to do but it is usual to align a gridsplitter with a column or row edge.
See
https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/how-to-resize-rows-with-a-gridsplitter
https://learn.microsoft.com/en-us/dotnet/framework/wpf/controls/how-to-resize-columns-with-a-gridsplitter
I have created a modal WPF window that looks as follows:
Here is the code for the window:
<Window x:Class="Dionysus.Core.Controls.ModalWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="ModalWindow" AllowsTransparency="True" Background="Transparent" WindowStyle="None">
<Grid Name="MainGrid">
<Rectangle Fill="Gray" Opacity="0.7" />
</Grid>
The "ErrorControl" is then added as follows:
MainGrid.Children.Add(uc);
The problem is as soon as I expand the stack trace, the controls transparency also changes:
I am assuming this has something to do with the ScrollViewer that uses the incorrect transparency, ie of the Rectangle instead of the containing Window.
I have also set the Opacity of the UserControl which owns the ScrollViewer to 1 and then binded the Opacity:
<ScrollViewer Background="WhiteSmoke" Opacity="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}, Path=Opacity}">
Can anyone help me?
--
UPDATE
Here is the code for the UserControl that is inserted into the Window
<Grid x:Name="LayoutRootx" Background="WhiteSmoke">
<StackPanel VerticalAlignment="Stretch">
<TextBlock TextWrapping="Wrap" Margin="5" Text="An error has occured:" Foreground="Black" FontSize="15" FontWeight="Medium"/>
<TextBlock TextWrapping="Wrap" Margin="5,10,5,5" Text="{Binding Error}"/>
<odc:OdcExpander Header="Stack Trace" Margin="5" IsExpanded="False" Background="WhiteSmoke">
<TextBox Text="{Binding StackTrace}" TextWrapping="Wrap" Margin="5,10,5,5" IsReadOnly="True" MaxHeight="370"/>
</odc:OdcExpander>
<odc:OdcExpander Header="Comment" Margin="5" IsExpanded="False">
<TextBox Text="{Binding Comment}" TextWrapping="Wrap" Margin="5,10,5,5" MaxHeight="370" Name="txtComment"/>
</odc:OdcExpander>
<StackPanel Margin="5,10,5,5" Orientation="Horizontal" HorizontalAlignment="Left">
<Button Style="{StaticResource DionysusButton}" Width="100" Height="23" IsDefault="True" Name="btnSendError">
<StackPanel Orientation="Horizontal">
<Image Source="/Dionysus.Shell;component/Images/camera-icon.png" Margin="0,0,5,0">
</Image>
<TextBlock Text="Send to IT" VerticalAlignment="Center"/>
<core:DionysusTriggerAction Height="0" Width="0" TargetControl="{Binding ElementName=btnSendError}" MethodName="SendError"></core:DionysusTriggerAction>
</StackPanel>
</Button>
<Button Style="{StaticResource DionysusButton}" Width="100" Height="23" Name="btnExit" Margin="10,0,0,0" IsCancel="True">
<StackPanel Orientation="Horizontal">
<Image Source="/Dionysus.Shell;component/Images/DeleteRed.png" Margin="0,0,5,0">
</Image>
<TextBlock Text="Close" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<core:DionysusTriggerAction Height="0" Name="triggerAction2" Width="0" TargetControl="{Binding ElementName=btnExit}" MethodName="Exit"></core:DionysusTriggerAction>
</StackPanel>
</StackPanel>
</Grid>
If your window has a fixed size and cannot be resized, you can use the following trick:
<Grid>
<Border BorderThickness="100" BorderBrush="Gray" Opacity="0.7">
<Grid Background="White" Grid.Column="1" Grid.Row="1" x:Name="contentPlaceHolder">
<TextBlock Text="HELLO WORLD" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Border>
</Grid>
However, it is unlikely that your Window will always have the same size, so to make it more dynamic, you could change the layout of the Window as follows:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="YourDesiredSize"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="YourDesiredSize"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="0" Grid.ColumnSpan="3"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="2" Grid.ColumnSpan="3"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="1" Grid.Column="0"/>
<Rectangle Fill="Gray" Opacity="0.7" Grid.Row="1" Grid.Column="2"/>
<Grid Grid.Column="1" Grid.Row="1" Background="White" x:Name="contentPlaceHolder">
<TextBlock Text="HELLO WORLD" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Grid>
</Grid>
The result of this window placed on top of another looks more or less like this:
and then instead of adding to the MainGrid, add the UserControl to the contentPlaceHolder or however you want to call it:
contentPlaceHolder.Children.Add(uc);
Okay so I found a solution that works for me, I'm sure it's not the best but it might help someone having the same problem as I did.
The problem was that controls within my UserControl that I added to my Window were transparent, although I could not figure out the reason, I found a simple workaround.
By changing the OpacityMask property of the UserControl to whatever the required Background colour is, even if the controls opacity changes, it will be masked with the Brush that you supply.
uc.OpacityMask = Brushes.WhiteSmoke;
Hope it helps someone!
I have the following as a custom user control:
<UserControl x:Class="TestGUI.TBorder">
<Border Style="{StaticResource brdListBoxItem}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="5" />
<RowDefinition />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Style="{StaticResource tblTitleDataStyle}"
Text="{Binding Header, Mode=OneWay}" />
<Rectangle Grid.Row="1"
Grid.Column="0"
Margin="5,2"
Fill="{StaticResource BlueTextBrush}"
Height="1"
HorizontalAlignment="Stretch" />
<ContentPresenter Name="ccpMain"
Grid.Row="2"
Grid.Column="0"
Content="{Binding Content}" />
<!--<TextBlock Grid.Row="2"
Text="TEST HERE" />-->
</Grid>
</Border>
If I comment out the "ContentPresenter", and uncomment the "TextBlock", it appears as expected. If I have it as set, then only thing that displays is whatever is inside of the tags. For example:
<local:TBorder Grid.Row="2"
Grid.Column="0" Width="300"
Header="The Header">
<TextBlock Text="astnouhe" />
</local:TBorder>
displays only the "TextBlock".
Can someone explain this to me?
Thanks for any help.
What did you set the content to? If you are setting it to the XAML that you have in your question, then what it is doing is trying to display the text itself in your control.
You'll need to create another control that uses the XAML in your answer, and set that to the content of your user control in order to display those controls in side the user control.
I'm trying to make a list that is populated by external data and I have a datatemplate for it.
Each element of the list is composed of an image and two textblocks, and is linked to a specific page.
I'm trying to do this but when I wrap the structure with an HyperlinkButton, I just get a blank page.
I don't know if I'm doing something stupid wrong or it's not possible to have so many items in an HyperlinkButton. If it's not possible to do it this way, can someone guide me to the best solution to do this? Here's the code:
<Grid x:Name="ContentPanel" Margin="0,140,0,0" Background="White">
<ListBox HorizontalAlignment="Stretch" Name="itemList" VerticalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<HyperlinkButton>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" MinWidth="480">
<Grid.Background>
<ImageBrush ImageSource="/app;component/Images/degradat_cela.png" Stretch="UniformToFill" AlignmentY="Top" AlignmentX="Left" />
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="35" />
<RowDefinition Height="35" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="430*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Height="38" Width="38" Grid.RowSpan="2" Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="#FFFF003F" Padding="1">
<Image HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Name="listImage" Width="36" Height="36" Source="{Binding image}" />
</Border>
<TextBlock Margin="5 12 0 0" Grid.Column="1" Grid.Row="0" Name="title" Foreground="Black" Text="{Binding title}" FontWeight="Bold" FontSize="18" />
<TextBlock Margin="5 0 0 8" Grid.Column="1" Grid.Row="1" Name="description" Foreground="Black" Text="{Binding subtitle}" FontSize="14" />
</Grid>
</HyperlinkButton>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
I will also accept any suggestions to make my code better, as I'm new to .NET and I probably don't do things the best way!
Remove the HyperlinkButton and instead use the SelectionChanged event of the ListBox. So add this property to your ListBox:
SelectionChanged="myListBox_SelectionChanged"
Then in your code behind do this:
private void myListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if ((sender as ListBox).SelectedIndex == -1)
return;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?Index={0}",(sender as ListBox).SelectedIndex),System.UriKind.Relative));
}
This code assumes a drilldown page that uses a query string to change it's layout. This is just for example. If instead of index you wanted to reference some property of the bound item you could instead do something like this (assuming an ID property):
int itemID = ((sender as ListBox).SelectedItem as MyApp.Model.myItem).ID;
NavigationService.Navigate(new System.Uri(string.Format("/Drilldown.xaml?ID={0}",itemID),System.UriKind.Relative));