At the minute I have a view which populates a ListView with tiles bound to a list of users. OnClick of any of these Tiles(buttons) I need to dynamically create a small draggable window consisting of a StackPanel containing an ScrollViewer&ItemsControl, Textbox and Button. This will then have to be bound to an ObservableCollection based on which user Tile was clicked.
This will be used in a private chat scenario.
I have already implemented a group chat bound to an ObservableCollection but this is created on navigation to the page.
I have started by adding the same set of controls to a dataTemplate to Resources.xaml but am quite lost as to where to go next.
<DataTemplate x:Key="PrivateChatTemplate">
<StackPanel Width="267" Height="300" >
<ScrollViewer x:Name="PrivateScrollViewer" Grid.ColumnSpan="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" >
<ItemsControl Name="PrivateItemsControl" Foreground="Black" />
</ScrollViewer>
<TextBox x:Name="PrivateTextBox" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Width="201" Height="60" BorderThickness="1" BorderBrush="Black"/>
<Button x:Name="PrivateSendButton" Content="Send" HorizontalAlignment="Left" Height="58" Margin="65,2,0,0" VerticalAlignment="Top" Width="66" Click="PrivateSendButton_Click" Background="Black"/>
</StackPanel>
</DataTemplate>
Thanks for any help.
Funny you mentioned a ScrollViewer since that gave me an idea for using a ScrollViewer to position a foreground window-like control in front of other content and it's fairly simple.
Inside your page - put a ScrollViewer that extends to the full size of the app window (by setting both VerticalAlignment and HorizontalAlignment to Stretch), that has a Panel like a Canvas or Grid inside of it and place the window/UserControl inside of it - like the Rectangle in the code below. Make sure the ScrollViewer can scroll both ways by setting the -ScrollMode/-ScrollBarVisibility values and the size of the panel to be larger than the ScrollViewer's ViewportWidth and ViewportHeight. You should handle SizeChanged event on the ScrollViewer and the window inside of it and set the panel's Width and Height to something like
panel.Width = scrollViewer.ViewportWidth * 2 - window.ActualWidth;
panel.Height = scrollViewer.ViewportHeight * 2 - window.ActualWidth;
Now everything should become scrollable by touch. The remaining problem is handling mouse input which you can do based on Pointer- events on the window.
XAML
<Page
x:Class="DraggableWindow.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DraggableWindow"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Button
Content="Button"
HorizontalAlignment="Left"
Height="99"
Margin="112,101,0,0"
VerticalAlignment="Top"
Width="119" />
<Button
Content="Button"
HorizontalAlignment="Left"
Height="147"
Margin="985,389,0,0"
VerticalAlignment="Top"
Width="262" />
<Button
Content="Button"
HorizontalAlignment="Left"
Height="147"
Margin="403,581,0,0"
VerticalAlignment="Top"
Width="262" />
<Button
Content="Button"
HorizontalAlignment="Left"
Height="147"
Margin="112,277,0,0"
VerticalAlignment="Top"
Width="262" />
<Button
Content="Button"
HorizontalAlignment="Left"
Height="147"
Margin="682,129,0,0"
VerticalAlignment="Top"
Width="262" />
<Button
Content="Button"
HorizontalAlignment="Left"
Height="147"
Margin="551,371,0,0"
VerticalAlignment="Top"
Width="262" />
<ScrollViewer
x:Name="scrollViewer"
SizeChanged="OnScrollViewerSizeChanged"
Background="{x:Null}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalScrollMode="Auto"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
IsHorizontalRailEnabled="False"
IsVerticalRailEnabled="False">
<Canvas
x:Name="panel">
<Rectangle
x:Name="window"
SizeChanged="OnWindowSizeChanged"
PointerPressed="OnWindowPointerPressed"
PointerMoved="OnWindowPointerMoved"
PointerReleased="OnWindowPointerReleased"
Fill="LightGray"
Width="200"
Height="150"/>
</Canvas>
</ScrollViewer>
</Grid>
</Page>
C#
using Windows.Devices.Input;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
namespace DraggableWindow
{
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private uint pointerId;
private Point lastPoint;
private void OnWindowPointerPressed(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerDeviceType == PointerDeviceType.Mouse)
{
window.CapturePointer(e.Pointer);
this.pointerId = e.Pointer.PointerId;
this.lastPoint = e.GetCurrentPoint(window).Position;
}
}
private void OnWindowPointerMoved(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.IsInContact &&
e.Pointer.PointerId == pointerId)
{
var point = e.GetCurrentPoint(window).Position;
this.scrollViewer.ChangeView(
this.scrollViewer.HorizontalOffset - point.X + lastPoint.X,
this.scrollViewer.VerticalOffset - point.Y + lastPoint.Y,
null,
true);
}
}
private void OnWindowPointerReleased(object sender, PointerRoutedEventArgs e)
{
if (e.Pointer.PointerId == pointerId)
{
window.ReleasePointerCapture(e.Pointer);
}
}
private void OnScrollViewerSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateWindowingLayout();
}
private void OnWindowSizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateWindowingLayout();
}
private void UpdateWindowingLayout()
{
this.panel.Width = this.scrollViewer.ViewportWidth * 2 - 0.0 * this.window.ActualWidth;
this.panel.Height = this.scrollViewer.ViewportHeight * 2 - 0.5 * this.window.ActualHeight;
Canvas.SetLeft(this.window, this.scrollViewer.ViewportWidth - 0.5 * this.window.ActualWidth);
Canvas.SetTop(this.window, this.scrollViewer.ViewportHeight - 0.5 * this.window.ActualHeight);
}
}
}
Oh and to make it all dynamic - wrap it in a UserControl to handle the events there and put that in a Popup. I'll see about wrapping all that in a reusable control when I get a chance, since I need something like that too for my visual tree debugger overlay.
#Filip Skakun Unfortunately I have to use 8.0 as opposed to 8.1, so don't have the new ChangeView method. I have attempted to make a custom UserControl but I'm not sure how to handle the SizeChanged and UpdateWindowingLayout since the windows will be created on click of a button essentially and dynamically created. I then need to bind a list of strings to the ItemsControl inside the UserControl.
`Unfortunately I have to use 8.0 as opposed to 8.1, so don't have the new ChangeView method. I have attempted to make a custom UserControl but I'm not sure how to handle the SizeChanged and UpdateWindowingLayout(to implement the dragging) since the windows will be created on click of a button essentially and dynamically created. I then need to bind a list of strings to the ItemsControl inside the UserControl. '
<UserControl
x:Class="KeyOui.View.PrivateChatWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:KeyOui.View"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="200"
d:DesignWidth="300">
<StackPanel Background="Indigo">
<ScrollViewer>
<ItemsControl Name="PrivateChatItemsControl" ItemsSource="{Binding ListOfMessages.Name}" Width="Auto" Height="150" Foreground="Black" BorderBrush="Gray" BorderThickness="2" />
</ScrollViewer>
<StackPanel VerticalAlignment="Stretch" Orientation="Horizontal" HorizontalAlignment="Stretch">
<TextBox x:Name="GroupChatTextBox" VerticalAlignment="Bottom" TextWrapping="Wrap" FontSize="14" Width="140" Height="40" Margin="5,5,5,5" BorderThickness="1" BorderBrush="Gray"/>
<Button x:Name="SendButton" Content="Send"
HorizontalAlignment="Left" Height="40"
VerticalAlignment="Top" Width="Auto"
Click="SendButton_Click" Margin="5,5,5,5"
BorderThickness="1" BorderBrush="Gray"/>
</StackPanel>
</StackPanel>
Related
I am new to WPF, and I am trying to make an RPG using 2D Sprite gif files for animations for walking forward, backward, etc.
I am having issues making the original picture move in any direction using the arrow keys. Here is the snippet of code:
<UserControl x:Class="TextofTheWild2._0.Screen1"
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:gif="https://github.com/XamlAnimatedGif/XamlAnimatedGif"
xmlns:local="clr-namespace:TextofTheWild2._0"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
FocusManager.FocusedElement = "{Binding ElementName=MyCanvas}">
<Canvas x:Name="MyCanvas" HorizontalAlignment="Right" Height="450" VerticalAlignment="Top" Width="800" Background="#FFFCD8A8" KeyDown="Canvas_OnKeyDown" Focusable="True" FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
<Grid HorizontalAlignment="Left" Height="190" VerticalAlignment="Top" Width="410" Background="#FF00A800" Canvas.Left="390"/>
<TextBlock Height="40" Canvas.Left="149" TextWrapping="Wrap" Text="Press E to activate" Canvas.Top="40" Width="52" FontFamily="Microsoft Sans Serif" Visibility="Collapsed"/>
<Grid HorizontalAlignment="Left" Height="190" VerticalAlignment="Top" Width="27" Background="#FF00A800"/>
<Grid HorizontalAlignment="Left" Height="26" VerticalAlignment="Top" Width="85" Background="Black" Canvas.Left="27" Canvas.Top="35"/>
<Grid HorizontalAlignment="Left" Height="35" VerticalAlignment="Top" Width="112" Background="#FF00A800"/>
<Grid HorizontalAlignment="Left" Height="181" VerticalAlignment="Top" Width="27" Background="#FF00A800" Canvas.Top="269"/>
<Grid HorizontalAlignment="Left" Height="181" VerticalAlignment="Top" Width="22" Background="#FF00A800" Canvas.Left="778" Canvas.Top="269"/>
<Grid HorizontalAlignment="Left" Height="80" VerticalAlignment="Top" Width="800" Background="#FF00A800" Canvas.Top="370"/>
<Image Name="Green_Link" Height="93" VerticalAlignment="Top" Canvas.Left="480" Canvas.Top="259" Width="85" gif:AnimationBehavior.SourceUri="Assets/Green Link idle.gif" Source="Assets/Green Link idle.gif" Focusable="True"/>
<Image Name="Blue_Link" Height="93" VerticalAlignment="Top" Canvas.Left="390" Canvas.Top="259" Width="85" gif:AnimationBehavior.SourceUri="Assets/Blue Link idle.gif" Source="Assets/Blue Link idle.gif"/>
<Image Name="Red_Link" Height="93" VerticalAlignment="Top" Canvas.Left="305" Canvas.Top="259" Width="85" gif:AnimationBehavior.SourceUri="Assets/Red Link Idle.gif" Source="Assets/Red Link Idle.gif"/>
<Image Name="Purple_Link" Height="93" VerticalAlignment="Top" Canvas.Left="220" Canvas.Top="259" Width="85" gif:AnimationBehavior.SourceUri="Assets/Purple Link idle.gif" Source="Assets/Purple Link idle.gif"/>
</Canvas>
</UserControl>
For XAML, and the code behind it:
public partial class Screen1 : UserControl
{
public Screen1()
{
InitializeComponent();
}
private void Canvas_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
Canvas.SetTop(Green_Link, Canvas.GetTop(Green_Link) + 10);
}
else if (e.Key == Key.Up)
{
Canvas.SetTop(Green_Link, Canvas.GetTop(Green_Link) - 10);
}
else if (e.Key == Key.Left)
{
Canvas.SetLeft(Green_Link, Canvas.GetLeft(Green_Link) - 10);
}
else if (e.Key == Key.Right)
{
Canvas.SetLeft(Green_Link, Canvas.GetLeft(Green_Link) + 10);
}
}
}
Before I start working on transitional animations, I would like to at least get the images to move in the canvas. Thanks!
Looks like you've put your C# code in the wrong place. The start of your XAML file says this:
<x:Name="WINDow" x:Class="TextofTheWild2._0.GameWindow" ...
This means that your xaml file is partially defining a class called GameWindow. This'll be made up of two files, the xaml and the codebehind (which has extension .xaml.cs). When you handle an event in xaml like you're doing (ie. KeyDown="Canvas_OnKeyDown"), it gets routed to a function in the codebehind for that view.
If you put your Canvas_KeyDown method in GameWindow.xaml.cs (and rename the method to Canvas_OnKeyDown - you were missing an On), WPF should pick up and it should work correctly.
Is there a way to add semi transparent layer for the application in UWP?
In normal .NET there is a possibility, but in UWP I cant find it.
I need this behavior, for make the whole application inactive except one control, and display a tooltip next to the control. It is need for tuturial in application
Thanks for everyone!
I'm imagining you need some sort of BlockUI/UnBlockUI behavior, not sure if there's a 3rd party for that, but you can be creative in order to achieve that.
By taking advantage of ZIndex, Opacity, DependencyProperty and some event handling, you can achieve that.
xaml
<Page x:Name="root"
x:Class="App1.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
d:DesignHeight="450" d:DesignWidth="800">
<Canvas Background="AliceBlue">
<Rectangle Canvas.Left="30" Canvas.ZIndex="{Binding BlockerZIndex, ElementName=root}" Width="180" Height="200" Fill="White" Opacity="0.5"/>
<Button Canvas.ZIndex="1" Canvas.Left="30" Canvas.Top="70" Content="Send Email" Width="150" Height="50" Background="Blue" Foreground="Black" />
<Button Canvas.ZIndex="1" Canvas.Left="30" Canvas.Top="140" Content="Print Receipt" Width="150" Height="50" Background="Blue" Foreground="Black" />
<Button x:Name="BlockUnBlockUIButton" Canvas.Left="30" Canvas.ZIndex="1" Canvas.Top="210" Width="150" Height="50" Background="Blue" Foreground="Black" Click="BlockUnBlockUIButton_OnClick" >
<TextBlock Text="Block/UnBlock UI" ToolTipService.ToolTip="Block/Unblock UI"/>
</Button>
</Canvas>
</Page>
code-behind
using Windows.UI.Xaml;
namespace App1
{
public sealed partial class MainPage
{
public MainPage()
{
InitializeComponent();
}
public static readonly DependencyProperty BlockerZIndexProperty =
DependencyProperty.Register(
nameof(BlockerZIndex),
typeof(int),
typeof(MainPage),
new PropertyMetadata(2));
public int BlockerZIndex
{
get => (int)GetValue(BlockerZIndexProperty);
set => SetValue(BlockerZIndexProperty, value);
}
private void BlockUnBlockUIButton_OnClick(object sender, RoutedEventArgs e)
{
BlockerZIndex = BlockerZIndex == 1 ? 2 : 1;
}
}
}
The Popup Placement Behavior Guide shows how to position a popup using several properties:
Placement
PlacementTarget
PlacmentRectangle
VerticalOffset/HorizontalOffset
Using these, we can set the target area, target origin, and placement alignment point. The guide goes on to describe a whole host of conditions for how the popup is placed in the event that it encounters the screen.
In my application, I created a popup programmatically as a response to user input and set the properties:
private void Button_Click(object sender, RoutedEventArgs e)
{
Popup popup = new Popup();
popup.Child = new PopupContent();
popup.Placement = PlacementMode.Right;
popup.PlacementTarget = redRectangle;
popup.StaysOpen = false;
popup.IsOpen = true;
}
The intended behavior was that the popup would appear on the right of rectangle. Instead I got this:
Why does the popup's placement alignment point change to the left side of the rectangle as if it has encountered the edge of the screen?
MVCE Resources:
<Window x:Class="PopupTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Width="700" Height="700">
<Grid>
<Button Click="Button_Click" Content="Create Popup" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Width="83" Height="25"/>
<Rectangle x:Name="redRectangle" Width="20" Height="20" Fill="Red"/>
</Grid>
</Window>
<UserControl x:Class="PopupTest.PopupContent"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="300">
<Border BorderBrush="Black" BorderThickness="2">
<Border BorderBrush="#FF50A0E0" BorderThickness="10" Background="White">
<Border BorderBrush="Black" BorderThickness="2" Padding="10">
<Label Content="Popup!" FontSize="70" VerticalContentAlignment="Center" HorizontalContentAlignment="Center"/>
</Border>
</Border>
</Border>
</UserControl>
First of all it's my first day using Xaml so this question might be dummy for you, but i totally got lost.
Overview
My technique is that i have MainWindow.xaml and it's split into three areas (using grid columns) the columns width being set automatically.
Based on some actions in the right column, the middle column with show a page let's say Page.xaml that exists in different namespace.
What i'm seeking for
The problem is i need to set the width and height for this page to be equal the middle column width and height as it will fit this area.
Notes
I have very small experience with xaml and binding techniques.
MainWindow.Xaml
<Window
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"
WindowState="Maximized"
ResizeMode="NoResize"
WindowStartupLocation="CenterScreen"
Title="MainWindow" d:DesignWidth="1366" d:DesignHeight="768">
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1.2*" x:Name="LeftColoumn" />
<ColumnDefinition Width="3*" x:Name="CenterColoumn" />
<ColumnDefinition Width=".8*" x:Name="RightColoumn" />
</Grid.ColumnDefinitions>
<ScrollViewer Grid.Column="2">
<StackPanel Orientation="Vertical" x:Name="RightStackPanel" Background="LightGray" >
<Border BorderBrush="{x:Null}" Height="50" >
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" TextWrapping="Wrap" FontWeight="SemiBold" FontStyle="Normal" Margin="3" FontSize="20" >Others</TextBlock>
</Border>
<Expander x:Name="Expander1" Header="Others" Margin="0,0,10,0">
<Button Margin="0,0,0,0" Width="{Binding ActualWidth, ElementName=RightStackPanel}" Background="White" Content="Add" Height="50" Click="Button_Click" ></Button>
</Expander>
</StackPanel>
</ScrollViewer>
<Frame Grid.Column="0" x:Name="LeftFrame" Background="LightGray" ></Frame>
<Frame Grid.Column="1" x:Name="CenterFrame" Background="DarkGray" ></Frame>
</Grid></Window>
Other Xaml file
<Page
x:Name="Page"
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"
mc:Ignorable="d"
Title="Any" d:DesignWidth="1364" d:DesignHeight="868"
>
<Grid>
<Frame Background="DarkGray" />
</Grid></Page>
MainWindow.xaml.cs
private void Button_Click(object sender, RoutedEventArgs e)
{
Frame middleFrame=CenterColumn;
Otherxaml other=new Otherxaml();
middleFrame.Source = new Uri("OtherxamlPage.xaml", UriKind.RelativeOrAbsolute);
}
Pertinent to your code snippet, you may place the OtherxamlPage.xaml inside the central frame and set the properties of that frame like shown below:
<Frame Grid.Column="1" x:Name="CenterFrame" VerticalAlignment="Stretch" VerticalContentAlignment="Center" HorizontalAlignment="Stretch" HorizontalContentAlignment="Center" Source="OtherxamlPage.xaml" Background="DarkGray" />
You can set the Source="OtherxamlPage.xaml" dynamically in event handler, e.g. Button.Click as per your example.
Alternatively, consider the creation of WPF UserControl (re: https://msdn.microsoft.com/en-us/library/cc294992.aspx) instead of that other XAML Window (or Page) and place it directly into the grid cell. In both cases set the content "Stretch" property in order to adjust its size automatically, thus you won't need to specify it in the code.
Hope this may help.
I'm trying to make a chat window, like IRC, in which the contents are shown from bottom to top, just like any chat window ever created.
This is my xaml, nothing fancy about it
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ee="http://schemas.microsoft.com/expression/2010/effects" xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" x:Class="TestChat.Chat"
Title="Chat" Height="700" Width="400" WindowStyle="ThreeDBorderWindow" ResizeMode="CanMinimize">
<Grid>
<RichTextBox x:Name="txtChat" HorizontalAlignment="Left" Height="644" Margin="0,10,0,0" VerticalAlignment="Top" Width="388" VerticalScrollBarVisibility="Auto">
<FlowDocument />
</RichTextBox>
</Grid>
</Window>
And i have a backgroundworker adding text to it
private void SendWorkerComplete(object s, ProgressChangedEventArgs args)
{
txtChat.AppendText(args.UserState.ToString());
txtChat.ScrollToEnd();
}
private void SendWorker_DoWork(object sender, DoWorkEventArgs e)
{
SendWorker.ReportProgress(0, (string)e.Argument);
}
The VerticalContentAlignment property set to bottom does not render the contents this way, how could this be done? is there a property for it or it has to be done programmatically?
Why bother with a RichTextBox? Just use a regular TextBox.
<Grid>
<TextBox x:Name="txtChat" VerticalScrollBarVisibility="Auto" Margin="10" Text="Hello" VerticalContentAlignment="Bottom" />
</Grid>
you've set margin-left to 545 that goes rich text box out of Window changing your code to something like this shows your control on bottom of window:
<RichTextBox x:Name="txtChat" HorizontalAlignment="Stretch" Height="42" VerticalAlignment="Bottom" Width="auto" VerticalScrollBarVisibility="Auto" Background="Yellow">
<FlowDocument />
</RichTextBox>