On my MainPage.xaml I have some custom UserControls which I want to be able to move all over the Grid surface. That is the reason why I am adding them all to TransformGroup:
this.transformGroup = new TransformGroup();
this.translation = new TranslateTransform();
this.scale = new ScaleTransform();
this.transformGroup.Children.Add(this.scale);
this.transformGroup.Children.Add(this.translation);
myCustomControl1.RenderTransform = this.transformGroup;
myCustomControl2.RenderTransform = this.transformGroup;
Now I can move all my custom controls what gives me "scrolling effect" on the Grid (something like scrolling the Bing Maps effect).
My problem is:
I want to be able to seperate my Custom control from the TransformGroup and move it independent from the rest. In myCustomControl.xaml.cs I have:
private void separateControlFromTransformGroup()
{
Grid parentGrid = (Grid)Parent;
this.transformGroup = (TransformGroup)this.RenderTransform;//backup copy of old transform group
newTransformGroup1 = new TransformGroup(); //new temporary transform group
TranslateTransform translation1 = new TranslateTransform();
CopyTranslateTransform((TranslateTransform)transformGroup.Children[1], translation1);//copy the values of transformGroup from the MainPage.xaml to temporary one (not reference)
ScaleTransform scale1 = new ScaleTransform();
CopyScale((ScaleTransform)transformGroup.Children[0], scale1);
newTransformGroup1.Children.Add(scale1);
newTransformGroup1.Children.Add(translation1);
foreach (myCustomControl brother in parentGrid.Children)
{
if (brother == this)
{
continue; (separate this control from the TransformGroup)
}
else
{
brother.RenderTransform = newTransformGroup1; //the rest of myCustromControls on the Grid in MainPage.xaml now have diffrent transform group. Now I can move selected control independent from the rest
}
}
}
After moving the separate myCustomControl (with new values) I can't connect it with the rest in a transformGroup and be able to move the all together againg. What should I Do? Is there any other way to make controls 'moveAble' on the Grid if none selected, or select just one if any selected?
Please help.
You should be creating a separate TransformGroupd for each user control. You might consider having a container control that you add all the user controls with it's own TransformGroup, this transform group will affect all the controls while the individual per control transform group is used to affect the individual controls.
You might also consider wiring this all together directly in XAML.
So the MainPage might have the layout Grid with a child Grid which acts as the container for all the Controls, this is what will be translated and scaled to affect all the child controls.
<UserControl x:Class="SilverlightApplication1.MainPage"
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"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid x:Name="Container">
<Grid.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="ContainerTranslation" />
<ScaleTransform x:Name="ContainerScale" />
</TransformGroup>
</Grid.RenderTransform>
</Grid>
</Grid>
</UserControl>
Then the child controls can be added to the Constainer, each with their own Translation and Scale transform. The child control might be something like this.
<UserControl x:Class="SilverlightApplication1.EntityControl"
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"
d:DesignHeight="50" d:DesignWidth="50"
Width="50" Height="50">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="Translation" />
<ScaleTransform x:Name="Scale" />
</TransformGroup>
</Grid.RenderTransform>
<Ellipse Stroke="Black" StrokeThickness="2" />
</Grid>
</UserControl>
The code behind can expose some properties that you can access to affect the Translation and Scaling of the Entity controls.
Related
Running off a tutorial from CodeProject I've succeeded in adding a WPF item to my Winforms project. My WinformsProject adds a slightly altered version of ElementHost, which contains a xaml object as a child from a separate project (with the alterations to ElementHost seemingly just to pass property and methods between the two projects).
My XAML code is:
<UserControl x:Class="WindowsFormsControlLibrary1.RoundedButtonWithSVG"
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:windowsformscontrollibrary1="clr-namespace:WindowsFormsControlLibrary1"
mc:Ignorable="d"
d:DesignHeight="50" d:DesignWidth="250">
<Grid>
<Button x:Name="myButton" HorizontalAlignment="Left" Background="White" Height="50" VerticalAlignment="Top" Width="250" BorderBrush="#FFBFBFBF" Click="myButton_Click">
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="5"/>
</Style>
</Button.Resources>
<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" Stretch="Uniform">
<Canvas Name="svg117" Width="32" Height="32" >
<!--Unknown tag: sodipodi:namedview-->
<Path xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Name="path115" Fill="#FF008A9F" StrokeThickness=".4025" Stroke="#FF008A9F">
<Path.Data> <!--Below is the SVG for an icon-->
<PathGeometry Figures="m31.63 0.27366c-0.12545-0.088189-0.29069-0.098564-0.4267-0.027534l-30.786 16.139c-0.19792 0.10375-0.27291 0.34517-0.16751 0.53991 0.048232 0.08899 0.12898 0.15682 0.22597 0.18955l9.4117 3.2015 0.17011 0.05507 2.6795 8.2814c0.04291 0.13288 0.1533 0.23384 0.2911 0.26696 0.03167 0.0072 0.06411 0.01117 0.09663 0.01117 0.10767 0 0.21091-0.0419 0.28704-0.11692l5.5775-5.4817 8.2128 2.7833c0.11327 0.03911 0.23872 0.02634 0.34144-0.03512 0.10272-0.06066 0.17295-0.16281 0.19203-0.27933l4.0599-25.14c0.02395-0.14964-0.04019-0.29968-0.16564-0.38747zm-30.003 16.381 26.809-14.053c0.0016-0.0012 0.0045-7.981e-4 0.0057 7.981e-4 0.0012 0.0016 8.12e-4 0.00439-8.12e-4 0.00559l-18.205 16.976-8.607-2.9218c-0.00231-7.98e-4 -0.00349-0.0032-0.00268-0.0056 2.842e-4 -7.98e-4 8.12e-4 -0.0016 0.00146-2e-3zm9.2038 3.4745 17.873-16.667c0.0016-0.0016 0.0041-0.0016 0.0057 0 2e-3 0.0012 2e-3 0.00399 4.06e-4 0.00559l-13.97 17.868c-0.0311 0.03871-0.05387 0.0834-0.06699 0.13129l-1.5805 5.6265c0 2e-3 -0.0018 4e-3 -0.0041 4e-3 -0.0022 0-0.0041-2e-3 -0.0041-4e-3zm3.077 7.0571 1.4303-5.0918 2.7969 0.94773-4.2223 4.1481c-0.0022 3.99e-4 -0.0043-7.98e-4 -0.0048-0.0032-4.1e-5 -3.99e-4 -8.1e-5 -3.99e-4 -8.1e-5 -7.98e-4zm13.097-1.9821-11.277-3.8221 14.987-19.168c8.12e-4 -2e-3 0.0028-0.00279 0.0049-2e-3 2e-3 7.981e-4 0.0028 0.00279 2e-3 0.00479l-3.712 22.984c-4.06e-4 2e-3 -0.0024 0.0036-0.0049 0.0032z" FillRule="NonZero"/>
</Path.Data>
</Path>
</Canvas>
</Viewbox>
</Button>
</Grid>
</UserControl>
Essentially the above is just a simple button, with rounded corners and an SVG image (which would all make our UI Girl exceedingly happy). Now I need a bunch of these, each with different text and images. My question is, can I somehow override the xaml settings based on fields from the c# constructor? So in this case, can I override the Figures property of the PathGeometry in the Xaml to set whatever image I need for the given button? Something like the following as the .xaml.cs file
public partial class ComboBoxWithGrid : UserControl
{
public ComboBoxWithGrid(string imageString)
{
this.boundImageStringProperty = imageString;
InitializeComponent();
}
public string boundImageStringProperty = ""; //Can I Inject this into the xaml in any way?
public Action buttonClickEvent;
private void button_Click(object sender, RoutedEventArgs e)
{
buttonClickEvent();
}
}
Doing the above would let me use the one xaml object for most of my buttons, just with different constructor arguments but I'm afraid I'm not XAML Literate enough to figure any of this out, and most guides I find online detail how to send data from the xaml constructor to the c# base (not the other way around). Is any of this possible?
My goal is to attach a new image control while the application is running.
img = new System.Windows.Controls.Image();
img.Margin = new Thickness(200, 10, 0, 0);
img.Width = 32;
img.Height = 32;
img.Source = etc;
I've tried
this.AddChild(img);// says must be a single element
this.AddLogicalChild(img);// does nothing
this.AddVisualChild(img);// does nothing
It was never this difficult to add a element with forms.
How can I simply attach this new element to the main window (not another control) so that it will show up.
Solved it, I named the grid main, and from there I was able to access the children attribute and the add function
main.children.add(img);
<Window x:Class="Crysis_Menu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded" AllowsTransparency="False" Background="White" Foreground="{x:Null}" WindowStyle="SingleBorderWindow">
<Grid Name="main">
<Button Content="Run" Height="23" HorizontalAlignment="Left" Margin="12,12,0,0" Name="btnRun" VerticalAlignment="Top" Width="151" Click="btnRun_Click" />
<TextBox Height="259" HorizontalAlignment="Left" Margin="12,40,0,0" Name="tbStatus" VerticalAlignment="Top" Width="151" />
</Grid>
</Window>
You should have only one root element under window. Adding the image using this.AddChilda adds the image as child of window, but you probably have some other child defined(Grid for example). Give a name to this child (Grid in the example) and then in the code behind add the image to the Grid
Example :
<Window>
<Grid x:Name="RootGrid">
</Grid>
</Window>
Then in the code behind use
RootGrid.Children.Add(img);
What is this in your case? You can try this.Content = image; or this.Children.Add(image);
If your this is indeed a Window, you should know that Window can have only a single child, which you put into Content. If you want several items in Window, usually you put some appropriate container (for example, Grid or StackPanel) as Window's content, and add children to it.
Vlad got the solution. I used it :
var grid = this.Content as Grid;
// or any controls
Label lblMessage = new Label
{
Content = "I am a label",
Margin = new Thickness(86, 269, 0, 0)
};
grid.Children.Add(lblMessage);
I have done carousels in web development, but animating them in WPF through XAML or C# is new to me. There are examples on the web, but they either are outdated or not what I am looking for. Even when I play around with source code of other projects, it's not what I hope for.
I want to have images sliding left-to-right (horizontally) automatically. The user cannot interact with the images to stop the sliding. While I can do this manually in a ScrollViewer, the process is manual...
ScrollViewer doesn't have any dependencies for animation. I tried using this to see if it is possible, but the application would always crash. Example I used..
Another attempt I've tried is storing images in a StackPanel, making sure the StackPanel is the width of one of my images, then having DispatcherTimer set to animate the TranslateTransform's X property. But...that didn't go anywhere.
Using a ScrollViewer or StackPanel is not important at all. I just want to have a carousel-like effect automatically transitioning through images. Sort of like THIS
I'm currently using Visual Studio 2012 and 2013, if it helps.
Is there a way to do this?
I' ve prepared exemplary carousel in wpf. You might want to use the code in form of UserControl for instance. As you proposed I prepared carousel with use of StackPanel. Code of my form looks as follows:
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Storyboard x:Key="CarouselStoryboard">
<DoubleAnimation
Storyboard.TargetName="CarouselTransform"
Storyboard.TargetProperty="X"/>
</Storyboard>
</Window.Resources>
<Canvas>
<StackPanel Name="Carousel" Orientation="Horizontal">
<StackPanel.RenderTransform>
<TranslateTransform x:Name="CarouselTransform" />
</StackPanel.RenderTransform>
<Button Height="350" Width="525" Content="Page1"/>
<Button Height="350" Width="525" Content="Page2"/>
<Button Height="350" Width="525" Content="Page3"/>
</StackPanel>
<Button Click="Left_Click" Content="Left" HorizontalAlignment="Left" Margin="10,164,0,0" VerticalAlignment="Top" Width="45">
</Button>
<Button Click="Right_Click" Content="Right" HorizontalAlignment="Left" Margin="448,170,0,0" VerticalAlignment="Top" Width="45"/>
</Canvas>
</Window>
The Storyboard element within WindowResources defines animation to be performed. It will change X property of TranslationTransform applied to StackPanel "Carousel" - this will result in animated movement of that panel. 3 buttons within the panel simulates 3 panels of the carousel. At the bottom there are 2 buttons - one for moving left and second for moving right. There are callback methods bounded to them. Code behind of the form looks like that:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private int currentElement = 0;
private void Left_Click(object sender, RoutedEventArgs e)
{
if(currentElement < 2)
{
currentElement++;
AnimateCarousel();
}
}
private void Right_Click(object sender, RoutedEventArgs e)
{
if (currentElement > 0)
{
currentElement--;
AnimateCarousel();
}
}
private void AnimateCarousel()
{
Storyboard storyboard = (this.Resources["CarouselStoryboard"] as Storyboard);
DoubleAnimation animation = storyboard.Children.First() as DoubleAnimation;
animation.To = -this.Width * currentElement;
storyboard.Begin();
}
}
currentElement field holds information which panel is currently being displayed to the user. Method AnimateCarousel actualy starts the animation. It refers to Storyboard defined in Resources and sets its DoubleAnimation To property to the value to which Carousel panel should be moved. Then by calling Begin method on storyboard it performs animation.
I have here a User Control where I'd like to overlay over my current area. Except it isn't showing up.
Here is my code for SpatialMode.xaml:
<UserControl x:Class="FilteringModule.View.SpatialFilterMode"
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"
MouseDown="UserControl_MouseDown"
MouseUp="UserControl_MouseUp"
MouseMove="UserControl_MouseMove">
<Canvas x:Name="SpatialCanvas" Background="Wheat">
<Border
x:Name="dragSelectionBorder"
BorderBrush="Blue"
BorderThickness="1"
Background="LightBlue"
CornerRadius="1"
Opacity="0.5"
/>
</Canvas>
</UserControl>
And where I call it:
public void ShowSpatialFilterMode()
{
Console.WriteLine("SHOWING SPATIAL FILTER MODE?");
_spatialFilterMode = new SpatialFilterMode();
_spatialFilterMode.Visibility = Visibility.Visible;
}
It writes to the console so I know it's hitting it correctly, except it's not showing?
Any help would be GREATLY appreciated.
Thanks!
Where are you actually inserting it into the visual tree?
Grid.Children.Add(_spatialFilterMode);
Do you have to add the control to some parent container?
In C#, using WPF components, Is it possible to display a canvas (whose contents change at run time based on user input) at two positions on the screen? or in two windows? So basically, whatever happens in the canvas positioned at one place happens in the canvas positioned in the other place.
Do you need them both to be interactive?
If not, then you could use a VisualBrush to duplicate the Canvas to another location. The VisualBrush part won't be interactive, but it will mirror what happens on the other one.
So, there are 2 solutions :
create control containing your canvas & add them to required places and bind to your VM
use visualbrush as #Tim mentioned, example:
<Window x:Class="visualbrushmirroringstackoverflow.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<VisualBrush x:Key="MirrorBrush"
Visual="{Binding ElementName=TargetCanvas}" TileMode="None"
Stretch="None" AutoLayoutContent="False"/>
</Window.Resources>
<StackPanel>
<Button Click="Button_Click" Content="Add Random Rects" Margin="5"/>
<Border BorderThickness="1" BorderBrush="Black" Margin="5">
<Canvas x:Name="TargetCanvas" Width="100" Height="100"
Background="White" />
</Border>
<Border BorderThickness="1" BorderBrush="Black" Margin="5">
<Rectangle Width="100" Height="100"
Fill="{StaticResource MirrorBrush}" />
</Border>
</StackPanel>
handler in code behind:
private void Button_Click(object sender, RoutedEventArgs e)
{
var rnd = new Random();
var element = new Rectangle { Fill = Brushes.Black, Width = 5, Height=5 };
Canvas.SetLeft(element, rnd.Next(100));
Canvas.SetTop(element, rnd.Next(100));
TargetCanvas.Children.Add(element);
}
If you're populating and updating the Canvas through databinding, you can create a usercontrol that defines the Canvas and all of it's styles, templates etc and bind each instance of that usercontrol to the same source object. Even in different windows, because they are updating from the same object in memory they should appear synchronised.
I had a same problem where i was asked to display a canvas in other window while retaining the original canvas.
What i did and you can do is this:
Since a single child cannot have multiple parents so you can make a copy of your original by serializing them using XamlReader.Save.
Put this canvas in a ViewBox (so that it stretches to its parent). Set contents of new window as this ViewBox.
Canvas copycanvas = XamlReader.Parse(XamlWriter.Save(OriginalCanvas)) as Canvas;
ViewBox vb = new ViewBox() { Stretch.Uniform, Child = copyCanvas };
Windows newwin = new Window() { Content = vb };
newwin.ShowDialog();