Detect if TextBlock is visible in StackPanel - c#

I have a StackPanel with a variable height based on available screen height/resolution, and I need to fill it up with data. The tricky part is my data is very dynamic and has headers/areas with different margins so doing a simple show x items isn't reliable.
Is there a way to detect if a TextBlock is completely visible inside a StackPanel? I'd like to not have half cut off items displayed if possible.

So this is more complicated than you are probably considering. That's because there's a lot of work to determine if there is something in front of an item. However, at its simplest, to determine if an item is visible on the screen you can use this technique.
Using this XAML:
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible">
<Grid x:Name="MyGrid">
<StackPanel x:Name="MyStackPanel" Orientation="Horizontal" Background="Gray">
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
<Rectangle Height="200" Width="200" Margin="50" Fill="Black" />
</StackPanel>
</Grid>
</ScrollViewer>
Use this code behind:
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
foreach (var item in MyStackPanel.Children.OfType<Windows.UI.Xaml.Shapes.Rectangle>())
{
// the box around the child
var _ItemBounds = item.TransformToVisual(null).TransformBounds(new Rect(0, 0, item.ActualWidth, item.ActualHeight));
// the box around the screen
var _Intersection = Window.Current.Bounds;
_Intersection.Intersect(_ItemBounds);
if (_Intersection.Equals(_ItemBounds))
// full
item.Fill = new SolidColorBrush(Windows.UI.Colors.Green);
else if (_Intersection.Equals(Rect.Empty))
// none
item.Fill = new SolidColorBrush(Windows.UI.Colors.Red);
else
// partial
item.Fill = new SolidColorBrush(Windows.UI.Colors.Orange);
}
}
Hope that makes sense. I always prefer examples of explanations. When you run this, visible boxes are colored green, partials are orange, and out of bounds items are painted red. Pretty simple.
related: https://stackoverflow.com/a/1517794/265706

Related

Crop content of rounded-corner border with image out of border

I need to move and rotate the image outside of the rounded border
example:
In How to make the contents of a round-cornered border be also round-cornered? find answer:
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Border1}" />
</Grid.OpacityMask>
<Border x:Name="Border1" CornerRadius="30" Background="Green" />
<TextBlock Text="asdas das d asd a sd a sda" />
</Grid>
This works if the elements do not go out of bounds.
If using rotate and/or margin like this:
<Grid>
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=_border1}" />
</Grid.OpacityMask>
<Border x:Name="_border1"
BorderThickness="0"
CornerRadius="30"
Background="Green" />
<TextBlock Text="SomeText"
Foreground="Yellow" />
<Image Source="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
Margin="-5 0 0 0"
Height="20"
Width="55"
Stretch="UniformToFill"
VerticalAlignment="Top"
HorizontalAlignment="Left"
RenderTransformOrigin="0.5 0.5">
<Image.RenderTransform>
<RotateTransform Angle="-7" />
</Image.RenderTransform>
</Image>
</Grid>
The rounding is displaced
How can I crop the image like in the first example? Thanks for your help.
Something is going wrong with the viewport calculation of the VisualBrush. Not sure if that is a bug in WPF.
A workaround could be setting the viewport in absolute units, with Rectangle instead of a Border:
<Grid.OpacityMask>
<VisualBrush
Visual="{Binding ElementName=rect}"
ViewportUnits="Absolute"
Viewport="{Binding ElementName=rect, Path=RenderedGeometry.Rect}"/>
</Grid.OpacityMask>
<Rectangle x:Name="rect" RadiusX="30" RadiusY="30" Fill="Green"/>
Or simpler, with setting the Clip property instead of OpacityMask, but still supporting resize:
<Grid Clip="{Binding ElementName=rect, Path=RenderedGeometry}">
<Rectangle RadiusX="30" RadiusY="30" Fill="Green" x:Name="rect"/>
...
</Grid>
I managed to achieve the desired result using Clip instead of OpacityMask. Then all the elements that need to be cropped must be children of the Border. If your Border needs to be dynamic, you need to bind the dimensions of the RectangleGeometry to the dimensions of the Border using Converter.
<Grid>
<Border BorderThickness="0"
CornerRadius="30"
Background="Green">
<Border.Clip>
<RectangleGeometry RadiusX="30" RadiusY="30" Rect="0,0,500,400"/>
</Border.Clip>
<Grid>
<TextBlock Text="SomeText"
Foreground="Yellow"/>
<Image Source="https://ssl.gstatic.com/ui/v1/icons/mail/rfr/logo_gmail_lockup_default_1x_r2.png"
Margin="-5 0 0 0"
Height="20"
Width="55"
Stretch="UniformToFill"
VerticalAlignment="Top"
HorizontalAlignment="Left"
RenderTransformOrigin="0.5 0.5">
<Image.RenderTransform>
<RotateTransform Angle="-7"/>
</Image.RenderTransform>
</Image>
</Grid>
</Border>
</Grid>

How to get a not selected item from wpf's listview

I'm working on a image displayer and I custom a datatemplate of listview(it's the images container) with two overlapping button to show the image is liked or disliked, and I need to do something when I click them, but I found that the item won't be selected if I just click the button, this makes I cannot get the item of the button which i clicked
I've try to google it but there's no help, all answers I got need to get the selecteditem at first, but this is where the question is
this is my data template
<DataTemplate DataType="model:PictureViewModel">
<Grid x:Name="ImageContentPresenter" Width="150" Height="150">
<Border x:Name="Border1" CornerRadius="15" Background="#FAFAFC" />
<Grid Height="150" Width="150">
<Grid.OpacityMask>
<VisualBrush Visual="{Binding ElementName=Border1}" />
</Grid.OpacityMask>
<Border Background="#FAFAFC" x:Name="ImageCornerBorder"
CornerRadius="15,15,15,15" />
<Image x:Name="DisplayedImage" Stretch="Uniform"
Source="{Binding Path=ImageSource,Mode=OneWay,Converter={StaticResource BitmapImageConverter}}"
Loaded="DisplayedImage_OnLoaded">
<Image.OpacityMask>
<VisualBrush Visual="{Binding ElementName=ImageCornerBorder}" />
</Image.OpacityMask>
</Image>
<Grid HorizontalAlignment="Right" VerticalAlignment="Top" Width="30"
Height="30" Margin="0,10,10,0">
<Grid.Resources>
<util1:VisibilityConverter x:Key="VisibilityConverter" />
<mainWindow:ButtonType x:Key="LikeButtonType">Like</mainWindow:ButtonType>
<mainWindow:ButtonType x:Key="DisLikeButtonType">DisLike</mainWindow:ButtonType>
</Grid.Resources>
<Button x:Name="LikeButton" Style="{DynamicResource MaterialDesignToolButton}" Visibility="{Binding IsLiked,Converter={StaticResource VisibilityConverter},ConverterParameter={StaticResource LikeButtonType}}" Click="LikeButton_OnClick">
<Viewbox Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path
Data="M12.1,18.55L12,18.65L11.89,18.55C7.14,14.24 4,11.39 4,8.5C4,6.5 5.5,5 7.5,5C9.04,5 10.54,6 11.07,7.36H12.93C13.46,6 14.96,5 16.5,5C18.5,5 20,6.5 20,8.5C20,11.39 16.86,14.24 12.1,18.55M16.5,3C14.76,3 13.09,3.81 12,5.08C10.91,3.81 9.24,3 7.5,3C4.42,3 2,5.41 2,8.5C2,12.27 5.4,15.36 10.55,20.03L12,21.35L13.45,20.03C18.6,15.36 22,12.27 22,8.5C22,5.41 19.58,3 16.5,3Z"
Fill="Gray" />
</Canvas>
</Viewbox>
</Button>
<Button x:Name="DislikeButton" Style="{DynamicResource MaterialDesignToolButton}" Visibility="{Binding IsLiked,Converter={StaticResource VisibilityConverter},ConverterParameter={StaticResource DisLikeButtonType}}">
<Viewbox Width="24" Height="24">
<Canvas Width="24" Height="24">
<Path
Data="M12,21.35L10.55,20.03C5.4,15.36 2,12.27 2,8.5C2,5.41 4.42,3 7.5,3C9.24,3 10.91,3.81 12,5.08C13.09,3.81 14.76,3 16.5,3C19.58,3 22,5.41 22,8.5C22,12.27 18.6,15.36 13.45,20.03L12,21.35Z"
Fill="Crimson" />
</Canvas>
</Viewbox>
</Button>
</Grid>
</Grid>
</Grid>
</DataTemplate>
the LikeButton and DislikeButton are those two buttons, how exactly can I get the item where i clicked button is
You could access PictureViewModel object by accessing the DataContext property on the Button object in your LikeButton_OnClick method.
The ideal way would be to use Commands. You could have LikeCommand defined on the PictureViewModel itself and access it via this from the Command Handler.

Set xaml icon in fluentribbon button

I use fluentribbon and mahapps for my GUI and want to have a button in my ribbon with a icon. I want to use xaml icons like this (not a file). So i need to set Path in the fluent:Button. I tried the following but its not working - Button is
blank (no text and no icon shown):
<fluent:Button Name="Test">
<StackPanel VerticalAlignment="Stretch" HorizontalAlignment="Center">
<Path Width="40" Height="40" Stretch="Uniform" UseLayoutRounding="False" Fill="Black" Data="..."/>
<TextBlock><Run Text="Test Button"/></TextBlock>
</StackPanel>
</fluent:Button>
Update
Here is the complete code:
<Controls:MetroWindow x:Class="RibbonTestProj.View.RibbonTest"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:fluent="urn:fluent-ribbon"
Title="Ribbon Test" Height="474" Width="849" MinHeight="300" MinWidth="400" >
<Grid>
<fluent:Ribbon CanMinimize="False" CanQuickAccessLocationChanging="False" AutomaticStateManagement="false"
x:Name="ribbon">
<fluent:RibbonTabItem x:Name="test1TabItem"
Header="Test1"
KeyTip="I">
<fluent:RibbonGroupBox Header="Group1" Height="84" Width="248" TabIndex="0">
<fluent:Button Name="Test">
<StackPanel VerticalAlignment="Stretch"
HorizontalAlignment="Center">
<Path Width="40"
Height="40"
Stretch="Uniform"
Fill="Black"
Data="M 10,100 C 10,300 300,-200 300,100" />
<TextBlock><Run Text="Test Button" /></TextBlock>
</StackPanel>
</fluent:Button>
</fluent:RibbonGroupBox>
<fluent:RibbonGroupBox Header="Group2" VerticalAlignment="Stretch" Height="84" Width="98" TabIndex="1">
</fluent:RibbonGroupBox>
</fluent:RibbonTabItem>
<fluent:RibbonTabItem x:Name="test2TabItem"
Header="Test2"
KeyTip="O">
</fluent:RibbonTabItem>
</fluent:Ribbon>
</Grid>
</Controls:MetroWindow>
and here how it looks like (the Button is there and i can click on it but there is no text and no icon)
Sorry for the late response. It took me some time to get the library running. It seems that you could set the LargeIcon
<fluent:Button Name="Test">
<fluent:Button.LargeIcon>
<Path Width="40"
Height="40"
Stretch="Uniform"
Fill="Black"
Data="M 10,100 C 10,300 300,-200 300,100" />
</fluent:Button.LargeIcon>
Test Button 1
</fluent:Button>
Don't forget: You can always extract a Controls default template. You can than look up how the control is build inside. How to Extract Default Control Template In Visual Studio?

Best practise to navigation in windows phone 8.1[RT] xaml

Hello I am working with windows phone 8.1[RT] application , I simply navigate page only . but I found new option we can use Frame in xaml also like this
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="120"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Background="White">
</Border>
<Button Content="next" Click="Button_Click" Background="Black" />
<Grid Grid.Row="1">
<Frame x:Name="Page1Frame" Background="Black" >
<StackPanel>
<Rectangle Height="100" Width="100" Fill="Red" Margin="5" />
<Rectangle Height="100" Width="100" Fill="Red" Margin="5" />
<Rectangle Height="100" Width="100" Fill="Red" Margin="5" />
<Rectangle Height="100" Width="100" Fill="Red" Margin="5" />
</StackPanel>
</Frame>
</Grid>
</Grid>
and navigate this frame like this
private void Button_Click(object sender, RoutedEventArgs e)
{
Page1Frame.Navigate(typeof(BlankPage1));
}
in this example my 120 height grid remain same and just navigate the frame .
I just want to know which is best practice to use ?
Thank you.
Page is page, Frame is frame, they are different.
Suppose your current page named MainPage, if you want to stay in MainPage and change the content of grid in root grid's row 1, you should use:
Page1Frame.Navigate(typeof(BlankPage1));
If you want to leave MainPage to go to another page, you should use:
var rootFrame = Window.Current.Content as Frame;
rootFrame.Navigate(typeof(BlankPage1));
and in this case, what you see is a blank page without 120 height grid remain.

Recolor region of image in C#

I'm working on building a diagnostic reader for my car. I can parse the messages from my OBD port but I want to create a display that is better than just a text readout. I want a graphical display of my car that will highlight the affected areas of the diagnostics. So if the tire pressure is low I want the tires on a picture of the car to turn red. I want to develop this in C# since that is what I'm the most familiar with. Any suggestions on what might be the best way to do this? It would also be nice if the method scaled with resizing the window.
<Image x:Name ="Bubble" Height="445" HorizontalAlignment="Left" Margin="42,12,0,0" Stretch="Fill" VerticalAlignment="Top" Width="654" Source="/WpfApplication1;component/Images/bubble.png" Panel.ZIndex="0" Opacity="1"/>
<Image x:Name="Smiley" Height="445" HorizontalAlignment="Left" Margin="42,12,0,0" Stretch="Fill" VerticalAlignment="Top" Width="654" Source="/WpfApplication1;component/Images/bubble.png" Panel.ZIndex="1" Opacity="0"/>
<Button Content="Button" Height="35" HorizontalAlignment="Left" Margin="10,46,0,0" Name="button1" VerticalAlignment="Top" Width="24" Click="button1_Click" />
<Button Content="Button" Height="50" HorizontalAlignment="Left" Margin="14,118,0,0" Name="button2" VerticalAlignment="Top" Width="22" Click="button2_Click" />
And then to change the opacity.
Bubble.Opacity = 0.0;
Smiley.Opacity = 1.0;
One way of doing this is having multiple images, and fading the opacity. You just need to make sure the image format supports transparency (png-s do nicely). Let's say you have a car image, and separate overlays for front and rear wheel. Keeping all images the same size for easy alignment.
You'll get something like
<Image x:Name="car" Source="car.png" Panel.ZIndex="0"/>
<Image x:Name="frontwheel" Source="frontwheel.png" Panel.ZIndex="1" Opacity="0"/>
<Image x:Name="rearwheel" Source="readwheel.png" Panel.ZIndex="2" Opacity="0"/>
Then in the code
frontwheel.Opacity=1.0;
Edit: here's a snippet from some code of mine. I add graphics to the canvases in the code-behind
<Grid Margin="20">
<Image Name="image1" Width="640" Height="640"
Opacity="{Binding Path=Value, ElementName=OpSlider}"
HorizontalAlignment="Center"
/>
<Canvas Name="MarkerLayer"
Opacity="{Binding Path=Value, ElementName=DotOverlaySlider}"
/>
<Canvas x:Name="Squares"
Opacity="{Binding Path=Value, ElementName=OverlayOpSlider}"
/>
</Grid>
Opacity here is bound to sliders
<Slider x:Name="OpSlider" Width="150" SmallChange="0.05" Maximum="1" Value="0.5" />
<Slider x:Name="OverlayOpSlider" Width="150" SmallChange="0.05" Maximum="1" Value="1" />
<Slider x:Name="DotOverlaySlider" Width="150" SmallChange="0.05" Maximum="1" Value="0.8" />

Categories

Resources