I'm creating a custom WPF window with, WindowStyle=None, AllowsTransparency=True, and ResizeMode = CanMinimize.
I have two events(That I created to understand events in WPF), PreviewMouseDoubleClick and PreviewMouseMove.
Here's the XAML:
<Style TargetType="{x:Type local:CustomWindow}">
<Setter Property="WindowStyle" Value="None"/>
<Setter Property="AllowsTransparency" Value="True"/>
<Setter Property="ResizeMode" Value="CanMinimize"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomWindow}">
<Border BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Grid Background="{TemplateBinding GridBackground}">
<ContentPresenter/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Here's the Code Behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
namespace CustomWindows
{
public class CustomWindow : Window
{
/* Dependency properties */
public Brush GridBackground
{
get { return (Brush)GetValue(GridBackgroundProperty); }
set { SetValue(GridBackgroundProperty, value); }
}
// Using a DependencyProperty as the backing store for GridBackground. This enables animation, styling, binding, etc...
public static readonly DependencyProperty GridBackgroundProperty =
DependencyProperty.Register("GridBackground", typeof(Brush), typeof(Window), new PropertyMetadata(null));
/* Constructors */
static CustomWindow()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomWindow), new FrameworkPropertyMetadata(typeof(CustomWindow)));
}
/* overriders */
public override void OnApplyTemplate()
{
PreviewMouseDoubleClick += (s, e) =>
{
WindowState = (WindowState == WindowState.Maximized) ? WindowState.Normal : WindowState.Maximized;
};
PreviewMouseMove += (s, e) =>
{
if(Mouse.LeftButton == MouseButtonState.Pressed)
{
DragMove();
}
};
base.OnApplyTemplate();
}
}
}
On Dragging this window, it covers the taskbar. I am not sure as to why.
Here's the link of the image that describes the behavior I'm talking about:
http://imgur.com/ba3ADoL Issue Description Image
Also on restoring the window, if the mouse pointer is out of bounds of the window, the focus is still not given to Desktop. If the mouse is manually moved a bit later. Focus is given to Desktop. This behavior seems strange to me. Any help will be greatly appreciated.
Thanks in Advance.
I would rather use WindowChrome class in an answer by dss539 at: How to create custom window chrome in wpf?
.NET 4.5 added a new class that greatly simplifies this.
The WindowChrome class enables you to extend Windows Presentation Foundation (WPF) content into the non-client area of a window that is typically reserved for the operating system’s window manager.
You can find a tutorial here.
And here's a short example usage.
Related
I have some problems with understanding how Hub Control is built.
The main idea of what I want to understand is how to build a custom control which allows to perform some gestures and which will not block controls inside.
Using Hub control I can press a Button and see its callback (color and size changing) and then move pointer left slide the Hub control.
Sorry about this such a stupid question but I don't have enough experience to find any responses by myself. Thanks in advance about any advice.
The main problem was associated with using of GestureRecognizer.
I have fixed my problem refusing to use GestureRecognizer and starting to use Manipulation Events over the main container.
The simplified template code:
<Style TargetType="my:CustomHub">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="my:CustomHub">
<Grid x:Name="RootGrid">
<ContentPresenter x:Name="MainPresenter"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Control's code-behind:
public sealed class CustomHub
{
public FrameworkElement Container { get; set; }
public MainView()
{
this.InitializeComponent();
}
private void InitGestureInteraction()
{
this.Container = (FrameworkElement)GetTemplateChild("RootGrid");
this.Container.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateRailsX;
this.Container.ManipulationStarted += (s, e) =>
{
};
this.Container.ManipulationDelta += (s, e) =>
{
var x = e.Cumulative.Translation.X;
// implementation of moving
};
this.Container.ManipulationCompleted += (s, e) =>
{
var x = e.Cumulative.Translation.X;
// implementation of moving
};
}
}
I am trying to address issues with the sensitivity of a capacitive touch screen where WPF buttons are being triggered if the users fingers pass too close to the surface of the screen.
This issue is that many users end up with fingers or parts of their hands, other than their primary touch finger, close to the surface of the screen and this causes incorrect buttons to be triggered.
Adjusting the sensitivity of the screen seems to make little difference to I thought I could try modifying the button pressed events to only trigger a Click if the button is pressed for more than a certain amount of time.
Can anyone explain how I might create a custom button that would have an adjustable 'pressed' time before triggering a Clicked event.
If possible perhaps you would be kind enough to include a very simple C#/WPF application with such a custom button.
EDIT
OK, so I have created a subclassed Button using the code below, as per #kidshaw's answer but I think I must be missing a few things because nothing is getting called except the default Click event.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace AppName
{
public class TouchButton : Button
{
DoubleAnimationUsingKeyFrames _animation;
public static readonly DependencyProperty DelayElapsedProperty =
DependencyProperty.Register("DelayElapsed", typeof(double), typeof(TouchButton), new PropertyMetadata(0d));
public static readonly DependencyProperty DelayMillisecondsProperty =
DependencyProperty.Register("DelayMilliseconds", typeof(int), typeof(TouchButton), new PropertyMetadata(100));
public double DelayElapsed
{
get { return (double)this.GetValue(DelayElapsedProperty); }
set { this.SetValue(DelayElapsedProperty, value); }
}
public int DelayMilliseconds
{
get { return (int)this.GetValue(DelayMillisecondsProperty); }
set { this.SetValue(DelayMillisecondsProperty, value); }
}
private void BeginDelay()
{
this._animation = new DoubleAnimationUsingKeyFrames() { FillBehavior = FillBehavior.Stop };
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(this.DelayMilliseconds)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.Completed += (o, e) =>
{
this.DelayElapsed = 0d;
//this.Command.Execute(this.CommandParameter); // Replace with whatever action you want to perform
Console.Beep();
this.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
};
this.BeginAnimation(DelayElapsedProperty, this._animation);
}
private void CancelDelay()
{
// Cancel animation
this.BeginAnimation(DelayElapsedProperty, null);
}
private void TouchButton_TouchDown(object sender, System.Windows.Input.TouchEventArgs e)
{
this.BeginDelay();
}
private void TouchButton_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
{
this.CancelDelay();
}
}
}
How does the TouchButton_TouchDown method ever get called ? Don't I have to assign this to the TouchDown even handler somehow?
OK, I added a constructor and set the TouchDown/Up event handlers so that works but the CancelDelay() does not stop the event from being fired. It seems work OK and gets called when the user lift their finger but does not prevent the event from being triggered.
A time delay button would be the best option.
I have provided an example in this other stack overflow answer.
It uses an animation to delay triggering a command.
Hope it helps.
Do wpf have touch and gold gesture
You could almost certainly come up with a solution to do this. There are two approaches I would look at:
Create a specialisation derived from Button. You would override various handlers to implement your own behaviour.
Create an attached dependency property that subscribes to the preview mouse events. The preview events would allow you to intercept the up/down events to inject your own behaviour before the standard button handling can generate the click events.
Option #1 is probably the easiest to get your head around. The handling to generate click events lives in ButtonBase in both the OnMouseLeftButtonDown and OnMouseLeftButtonUp handlers. If you implement (override) your own version of both these handlers you should be able to fairly easily introduce a timer that only calls OnClick to generate the click event once a certain time has expired since the user pressed (and held down) the button.
PS: If you don't have it already, I highly recommend you get a copy of .NET Reflector. It will allow you to easily view the code for the WPF button implementation. I quickly used it to have a look at the WPF button implementation to get an idea of how it works in order to answer this question.
For completeness here is the full solution I used based on #kidshaw's original answer. Might save someone else some time fiddling around pulling the pieces together.
Note that I am getting VS Designer errors with it complaining about not finding the custom classes in the apps namespace. Strangely this does not seem to happen on an earlier version of VS so perhaps its a bug in VS.
TouchButton.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;
namespace TouchButtonApp
{
public class TouchButton : Button
{
DoubleAnimationUsingKeyFrames _animation;
bool _isCancelled = false;
public static readonly DependencyProperty DelayElapsedProperty =
DependencyProperty.Register("DelayElapsed", typeof(double), typeof(TouchButton), new PropertyMetadata(0d));
public static readonly DependencyProperty DelayMillisecondsProperty =
DependencyProperty.Register("DelayMilliseconds", typeof(int), typeof(TouchButton), new PropertyMetadata(Properties.Settings.Default.ButtonTouchDelay));
public static readonly DependencyProperty IsTouchedProperty =
DependencyProperty.Register("IsTouched", typeof(bool), typeof(TouchButton), new PropertyMetadata(false));
// Create a custom routed event by first registering a RoutedEventID
// This event uses the bubbling routing strategy
public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent(
"Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TouchButton));
public TouchButton()
{
this.TouchDown +=TouchButton_TouchDown;
this.TouchUp +=TouchButton_TouchUp;
}
// Provide CLR accessors for the event
public event RoutedEventHandler Tap
{
add { AddHandler(TapEvent, value); }
remove { RemoveHandler(TapEvent, value); }
}
// This method raises the Tap event
void RaiseTapEvent()
{
if (!_isCancelled)
{
//Console.Beep();
this.IsTouched = true;
Console.WriteLine("RaiseTapEvent");
RoutedEventArgs newEventArgs = new RoutedEventArgs(TouchButton.TapEvent);
RaiseEvent(newEventArgs);
}
}
public bool IsTouched
{
get { return (bool)this.GetValue(IsTouchedProperty); }
set { this.SetValue(IsTouchedProperty, value); }
}
public double DelayElapsed
{
get { return (double)this.GetValue(DelayElapsedProperty); }
set { this.SetValue(DelayElapsedProperty, value); }
}
public int DelayMilliseconds
{
get { return (int)this.GetValue(DelayMillisecondsProperty); }
set { this.SetValue(DelayMillisecondsProperty, value); }
}
//Start the animation and raise the event unless its cancelled
private void BeginDelay()
{
_isCancelled = false;
Console.WriteLine("BeginDelay ");
this._animation = new DoubleAnimationUsingKeyFrames() { FillBehavior = FillBehavior.Stop };
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(this.DelayMilliseconds)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.Completed += (o, e) =>
{
this.DelayElapsed = 0d;
//this.Command.Execute(this.CommandParameter); // Replace with whatever action you want to perform
RaiseTapEvent();
this.IsTouched = false;
};
this.BeginAnimation(DelayElapsedProperty, this._animation);
}
private void CancelDelay()
{
// Cancel animation
_isCancelled = true;
Console.WriteLine("CancelDelay ");
this.BeginAnimation(DelayElapsedProperty, null);
}
private void TouchButton_TouchDown(object sender, System.Windows.Input.TouchEventArgs e)
{
this.BeginDelay();
}
private void TouchButton_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
{
this.CancelDelay();
}
}
}
Custom animation when IsTouched event is triggered in App.xaml
<Style x:Key="characterKeyT" TargetType="{x:Type local:TouchButton}">
<Setter Property="Focusable" Value="False" />
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="Margin" Value="6,4,8,4"/>
<Setter Property="FontSize" Value="24"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TouchButton}">
<Grid x:Name="grid">
<Border x:Name="border" CornerRadius="0">
<Border.Background>
<SolidColorBrush x:Name="BackgroundBrush" Color="{Binding Source={StaticResource settingsProvider}, Path=Default.ThemeColorPaleGray2}"/>
</Border.Background>
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextElement.Foreground="Black"
TextElement.FontSize="24"></ContentPresenter>
</Border>
</Grid>
<ControlTemplate.Resources>
<Storyboard x:Key="FadeTimeLine" BeginTime="00:00:00.000" Duration="00:00:02.10">
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color"
To="#FF22B0E6"
Duration="00:00:00.10"/>
<ColorAnimation Storyboard.TargetName="BackgroundBrush" Storyboard.TargetProperty="Color"
To="#FFECE8E8"
Duration="00:00:02.00"/>
</Storyboard>
</ControlTemplate.Resources>
<ControlTemplate.Triggers>
<Trigger Property="IsTouched" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Storyboard="{StaticResource FadeTimeLine}"/>
</Trigger.EnterActions>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource ThemeSolidColorBrushPaleGray}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" TargetName="border" Value="{StaticResource ThemeSolidColorBrushPaleGray2}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" TargetName="grid" Value="0.25"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
XAML Usage
<UserControl x:Class="TouchButtonApp.Keyboard1"
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:local="clr-namespace:TouchButtonApp"
mc:Ignorable="d"
d:DesignHeight="352" d:DesignWidth="1024">
<Grid>
<Grid Margin="0,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="90*"/>
<RowDefinition Height="90*"/>
<RowDefinition Height="90*"/>
<RowDefinition Height="90*"/>
</Grid.RowDefinitions>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="8*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
<ColumnDefinition Width="93*"/>
</Grid.ColumnDefinitions>
<local:TouchButton x:Name="qButton" Tap="Button_Click" Content="Q" Grid.Row="1" Style="{DynamicResource characterKeyT}" />
<local:TouchButton x:Name="wButton" Tap="Button_Click" Content="W" Grid.Column="1" Grid.Row="1" Style="{DynamicResource characterKeyT}" />
...
I have over 1000 images to sort through. But just to simplify, suppose I have the following files on my hard drive:
C:\a.jpg
C:\b.jpg
C:\c.jpg
C:\d.jpg
C:\e.jpg
The program will determine which files need to be displayed and store them an array:
string[] filesToDisplay = new string[] { "C:\b.jpg", "C:\e.jpg" };
I would like to have a window open showing only contents of filesToDisplay as thumbnails, so I can then click and open them. This will allow me to only sort through the selected images, rather than all of them.
What I have tried so far:
So far I have tried to open an explorer window, but I cant figure out how to only select specific files. Using sometime like:
System.Diagnostics.Process.Start("explorer.exe", argument);
I have also considered using IExplorerBrowser but it seems very complicated and I'm not sure it it supports thumbnails?
Thanks for reading
I don't think there is a way to display certain Images only using Explorer, However you coul just add them to a ListBox and open the file on DoubleClick.
Rough WPF Example:
Code:
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfApplication13
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<string> _files = new ObservableCollection<string>();
private string _selectedFile;
public MainWindow()
{
InitializeComponent();
foreach (var file in Directory.GetFiles(#"C:\"))
{
Files.Add(file);
}
}
void Item_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
Process.Start(SelectedFile);
}
public ObservableCollection<string> Files
{
get { return _files; }
set { _files = value; }
}
public string SelectedFile
{
get { return _selectedFile; }
set { _selectedFile = value; NotifyPropertyChanged("SelectedFile"); }
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Xaml:
<Window x:Class="WpfApplication13.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="400" Width="400" Name="UI" WindowStartupLocation="CenterScreen">
<Grid DataContext="{Binding ElementName=UI}">
<ListBox ItemsSource="{Binding Files}" SelectedItem="{Binding SelectedFile}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<EventSetter Event="MouseDoubleClick" Handler="Item_MouseDoubleClick" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="Black" />
<Setter Property="Margin" Value="2" />
</Style>
</ListBox.Resources>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" ItemHeight="50" ItemWidth="50" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Margin="2"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
Result:
You could use the Directory-class (link) and
the GetFiles()-Method (link) to search for the files you want to display as thumbnails.
Those files you could show in a ListView.
Here you can find some hints of how to create the thumbnails for your files:Get thumbnail of any file, not only image files on Windows XP/Vista
If you only want to show image-files you can create your thumbnails in this way
Image image = Image.FromFile(fileName);
Image thumb = image.GetThumbnailImage(120, 120, ()=>false, IntPtr.Zero);
I am making this app for windows phone 7, what I do is retrieve all the images from camera roll, saved pictures and other folder and display them in the listbox inside a wrap panel so they are displayed side by side....the thumbnail of the images is actually displayed hear.....
but as the number of images are increasing UI gets very slow and scrolling takes time...
I read many post and other question I think data virtualization or lazy loading is what I need but I am not understanding how can I use it, I saw the post from shawn oster and peter torr.....
I use a backgroundworker to load the images...
here's how...
void backroungWorker1_DoWork(object sender, DoWorkEventArgs e)
{
Dispatcher.BeginInvoke(() =>
{
foreach (string fileName in fileStorage.GetFileNames("images//*.*"))
{
if (fileName == null)
break;
string filepath = System.IO.Path.Combine("images", fileName);
try
{
using (IsolatedStorageFileStream imageStream = fileStorage.OpenFile(filepath, FileMode.Open))
{
var imageSource = PictureDecoder.DecodeJpeg(imageStream);
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.SetSource(imageStream);
var item = new ImageToName { bmp = bitmapImage, FileName = fileName };
vltBitmapImage.Add(item);
imageStream.Dispose();
imageStream.Close();
}
}
catch
{
Exception x = new Exception();
}
}
if (vltBitmapImage.Count() != 0)
{
lone.Visibility = Visibility.Collapsed;
this.vaultbox.ItemsSource = vltBitmapImage;
}
else
lone.Visibility = Visibility.Visible;
});
}
any help is greatly appreciated.....
sorry for being a noob...
Try this sample from code project, it explain how it work and comes with a full sample project
See: Loading Data when the User scrolls to the end of the list
If you want to add a Lazy load to a listbox you must setup a listner for your list box and change the way you load data into your data model, so first lest set up at the XAML code for a listbox:
In your page resource add this style, and note the loaded event its include ("ScrollViewer_Loaded"):
...
<phone:PhoneApplicationPage.Resources>
<Style x:Key="BusinessListBoxStyle"
TargetType="ListBox">
<Setter Property="Background"
Value="Transparent" />
<Setter Property="Foreground"
Value="{StaticResource PhoneForegroundBrush}" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility"
Value="Auto" />
<Setter Property="BorderThickness"
Value="0" />
<Setter Property="BorderBrush"
Value="Transparent" />
<Setter Property="Padding"
Value="0" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<ScrollViewer x:Name="scrollViewer"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Foreground="{TemplateBinding Foreground}"
Padding="{TemplateBinding Padding}"
Loaded="ScrollViewer_Loaded">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>
...
The add a reference to your style for the listbox, and bind your itemsSource to a list of items from your viewModel.
...
<ListBox x:Name="myList"
ItemsSource="{Binding myDataSource}"
Style="{StaticResource BusinessListBoxStyle}">
...
Next you have to set some code that loads data into the datamodel, when you reach the end of the list element in the list (the datamodel start loading more data into the mode, adds more items) Lazyloading!!
The way i normaly do this is by listing to the vertical offset of the listbox's scrollbar, and if its is about 1/4 from the edge i starts loading more items into the datamodel.
In the ScrollViewer loaded handler i set up at VertialOffset listener, by using the DependencyProperty, see code below:
public static readonly DependencyProperty ListVerticalOffsetProperty =
DependencyProperty.Register(
"ListVerticalOffset",
typeof(double),
typeof(MyPage),
new PropertyMetadata(new PropertyChangedCallback(OnListVerticalOffsetChanged))
);
private ScrollViewer _listScrollViewer;
private void ScrollViewer_Loaded(object sender, RoutedEventArgs e)
{
_listScrollViewer = sender as ScrollViewer;
Binding binding = new Binding();
binding.Source = _listScrollViewer;
binding.Path = new PropertyPath("VerticalOffset");
binding.Mode = BindingMode.OneWay;
this.SetBinding(ListVerticalOffsetProperty, binding);
}
public double ListVerticalOffset
{
get { return (double)this.GetValue(ListVerticalOffsetProperty); }
set { this.SetValue(ListVerticalOffsetProperty, value); }
}
private double _lastFetch;
private static void OnListVerticalOffsetChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MyPage page = obj as MyPage;
ScrollViewer viewer = page._listScrollViewer;
if (viewer != null)
{
if (page._lastFetch < viewer.ScrollableHeight)
{
// Trigger within 1/4 the viewport.
if (viewer.VerticalOffset >= (viewer.ScrollableHeight - (viewer.ViewportHeight / 4)))
{
page._lastFetch = viewer.ScrollableHeight;
MyViewModel _tmpviewmodel = page.DataContext as MyViewModel;
if ((_tmpviewmodel != null) && (_tmpviewmodel.HasMoreItems))
_tmpviewmodel.GetMoreItems();
}
}
}
}
Note here i make use of a MyViewModel, that holds all the items the listbox i binded to, and has methods for load items from a database, the isolatedstore, the web or what ever your needs are.
You just have to find your way of only load a part of your data into the viewmodel. I your case i will first load a list of all the files you need to load (that is just to retreive the list from GetFileNames in the IsoLatedStore). Then mayby only loads 20 pics at the time!
Something that was working on VS2008 (framework 3.5) seems to not work on VS2010 (framework 4).
I need to change the style of a window at runtime (user preference).
In VS2008 this code was working:
Window1.xaml
<Window x:Class="StyleTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
ResizeMode="CanResizeWithGrip">
<Window.Style>
<Style TargetType="{x:Type Window}">
<Setter Property="MinWidth" Value="400" />
<Setter Property="Width" Value="500" />
<Setter Property="MinHeight" Value="400" />
<Setter Property="SizeToContent" Value="Height" />
</Style>
</Window.Style>
<Grid>
</Grid>
</Window>
Window1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xml;
using System.Windows.Markup;
using System.IO;
namespace StyleTest
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
Loaded += new RoutedEventHandler(ObjDialog_Loaded);
}
void ObjDialog_Loaded(object sender, RoutedEventArgs e)
{
XmlDocumentFragment frag = new XmlDocument().CreateDocumentFragment();
frag.InnerXml = "<Style TargetType=\"{x:Type Window}\" xmlns=\"http://schemas.microsoft.com/winfx/2006/xaml/presentation\"> " +
" <Setter Property=\"Height\" Value=\"200\" />" +
" <Setter Property=\"Width\" Value=\"200\" />" +
"</Style>";
XmlNode node = frag.FirstChild as XmlElement;
Style style = LoadXaml(node.OuterXml) as Style;
if (style != null)
Style = style;
UpdateLayout();
}
private object LoadXaml(string xaml)
{
Exception ex = null;
object o = LoadXaml(xaml, out ex);
if (ex != null)
throw ex;
return o;
}
public static object LoadXaml(string xaml, out Exception exception)
{
try {
ParserContext pc = new ParserContext();
pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
pc.XmlnsDictionary.Add("l", "http://www.teradp.com/schemas/GN4/1/WinUI");
pc.XmlnsDictionary.Add("c", "clr-namespace:TeraDP.GN4.Common;assembly=Common");
exception = null;
return XamlReader.Load(new MemoryStream(Encoding.UTF8.GetBytes(xaml)), pc);
}
catch (Exception ex) {
exception = ex;
}
return null;
}
}
}
When I run this code on Framework 3.5 the window is displayed with a size of 200x200.
When I run this code on Framework 4 thw window is displayed with a size of 500x400
The strangest thing is that if I add MinWidth and MinHeight to the style applied at runtime those attributes works correctly also in VS2010, while Width and Height seems to be ignored.
Do someone has a solution for this problem?
AFAIK to change how the window is shown and/or its size you should just implement ArrangeOverride OR set Height and Width directly (for example in the Loaded event handlet)...
EDIT - as per comment:
Applying XAML at runtime can open up several security problems so I would recommend not doing so or at least implement some security measures to prevent the dynamically loaded XAML from messing with the application... that said:
http://blogs.msdn.com/b/ashish/archive/2007/08/14/dynamically-loading-xaml.aspx
WPF: Changing Resources (colors) from the App.xaml during runtime
http://blog.xamltemplates.net/?p=20
http://www.mostlydevelopers.com/blog/post/2009/01/15/load-xaml-at-runtime.aspx
http://dotnetslackers.com/XAML/re-205412_Load_XAML_Resource_Dictionaries_at_Runtime.aspx
http://www.codeproject.com/KB/WPF/wpfskins.aspx
This MS Connect entry is not exactly the same issue but somehow related and suggests that there could be a bug in WPF 4.