Silverlight 4 баг за багом (шаг за шагом)

Posted in C#, Silverlight 4, XAML with tags , , , , , , on 31.05.2011 by prostocod

эх, первое знакомство с SL4 прошла довольно не успешно, найдено много багов или конкретных проблем.
Данная статья будет содержать конкретные проблемы, если я найду решения я буду выкладывать ссылку на её решение.

Поехали…

  • TabControl — не хочет делать binding. т.е если у вас есть Source, то вы не сможете сгенерировать TabItems использую стандартный способ. — решение
  • MultiBinding — мультибиндинг, просто нет в сборке — решение.
  • Binding в Canvas не работает позиционирование — вроде всё работает, нужно использовать ItemsControl, но вот самое главное не работает (Canvas.SetLeft Canvas.SetTop). — решение
  • Растягивание — ViewBox может и работает, но у меня пока не получилось его укратить.
  • DataGrid и культура ошибок — почему-то у меня появляются русские предупреждения при Validate
  •  TextBox\TextBlock и моментальный байдинг — через UpdateSourceTrigger=»PropertyChanged» не выйдет.
  • Entity Framework 4 и On Load Operation Completed — не совсем Silverlight, но очень нужно для работы с ним.

Это проблемы с которыми я столкнулся на днях. Есть и решенные проблемы, их тоже добавлю.

Если знаете ответ на решение этих проблем пишите, если есть другие проблемы, тоже пишите.

Картинка по умолчанию Silverlight 4

Posted in C#, Silverlight 4, XAML with tags , , , , on 09.06.2011 by prostocod

Думаю, у многих появляется ситуация с условием если картинки нету или картинка не загрузилась, указать defualt картинку.

Первое что приходит в голову это использовать Convert который будет заниматься этим делом.
Но увы я оказался не прав, этот вариант не очень хороший. Так как для этого действия есть специальное средство.

Есть у контрола Image событие ImageFailed — который происходит, когда картинка не загрузиться.

Использование:

<Image MaxHeight="50" x:Name="image" Source="{Binding photo">
	<i:Interaction.Triggers>
		<i:EventTrigger EventName="ImageFailed">
			<ei:ChangePropertyAction PropertyName="Source">
			    <ei:ChangePropertyAction.Value>
				<ImageSource>
				    /images/noimage.png
				</ImageSource>
			    </ei:ChangePropertyAction.Value>
			</ei:ChangePropertyAction>
		</i:EventTrigger>
	</i:Interaction.Triggers>
</Image>

Первое маленькое замечание, но важное.

Если ваша картинка находиться в интернете, т.е ссылка начинается http\www, то будет задержка на, то что бы отправить запрос и получить ответ, и только после этого будет отображена стандартная картинка.

И второе замечание.

Если путь к картинке будет равна null или String.Empty, то событие вообще не сработает.

Есть не сколько способов исправить это, я решил написать конвертор. Который если что то не так возвращает строку, которая обязательно не должна являться ссылкой, что бы не попасть под первое замечание.

Код конвертора:

    public class ConvertNullImage : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {

            if (value == null || value.ToString() == "")
                return "bad";
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter,
                                  CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Перемещение user control

Posted in C#, Silverlight 4, Windows Presentation Foundation (WPF), WPF для начинающих with tags , , , , , , , , on 09.06.2011 by prostocod

У меня стояла задача, сделать обычное перемещение в Silverlight 4.
Была не большая проблема, но я решил и выкладываю код.

Создаем User Contorl у него создаем 3 события, с которыми мы и будем работать.
Я создаю декларативно в XAML, но вы можете его создать и в коде.

    MouseLeftButtonDown="RootMouseLeftButtonDown"
    MouseLeftButtonUp="RootMouseLeftButtonUp"
    MouseMove="RootMouseMove" 

А в код добавляем такой не сильно заумный код

        Point m_anchorPoint;
        Point m_currentPoint;
        bool isDrag = false;
        private void RootMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var element = sender as FrameworkElement;
            m_anchorPoint = e.GetPosition(null);
            element.CaptureMouse();
            isDrag = true;
            e.Handled = true;
        }

        private readonly TranslateTransform m_transform = new TranslateTransform();
        private void RootMouseMove(object sender, MouseEventArgs e)
        {
            if (isDrag)
            {
                m_currentPoint = e.GetPosition(null);

                m_transform.X += m_currentPoint.X - m_anchorPoint.X;
                m_transform.Y += (m_currentPoint.Y - m_anchorPoint.Y);

                this.RenderTransform = m_transform;
                m_anchorPoint = m_currentPoint;
            }
        }

        private void RootMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            if (isDrag)
            {
                var element = sender as FrameworkElement;
                element.ReleaseMouseCapture();
                isDrag = false;
                e.Handled = true;
            }
        }

В данном примере я двигаю использую трансформацию, но если ваш элемент лежит в Canvas вы можете изменять положения свойствами Canvas.SetLeft() Canvas.SetTop().

Правда есть тут на первый взгляд не понятные строчки.

e.Handled = true; — указывает на то что не надо передавать событие в обработчик базового класса.
element.CaptureMouse(); и element.ReleaseMouseCapture(); — работают в паре один задает захват элемента, другой освобождает. Подробнее system.windows.uielement.capturemouse

Binding canvas в Silverlight 4 (баг №3)

Posted in Uncategorized on 03.06.2011 by prostocod

Продолжение статьи Silverlight 4 баг за багом

Описание проблемы:

У меня была задача, построить элементы на панеле canvas. У меня была Source котороый хранил кординаты элементов и их нужно было отобразить на экране с помощью Canvas.SetLeft и Canvas.SetTop — увы это не работает.

Решение проблемы:
Решение нашел Mikle. Решение довольно простое, использовать TranslateTransform вместо позиционирования канваса.
В итоге получился такой код:

<ItemsControl ItemsSource="{Binding Table}">
    <ItemsControl.ItemsPanel>
	<ItemsPanelTemplate>
	    <Canvas Margin="10" Background="AliceBlue"   Width="300" Height="300" />
	</ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
    <ItemsControl.ItemTemplate>
	<DataTemplate>
	    <Border MouseLeftButtonDown="Border_MouseLeftButtonDown">
		<StackPanel>
		    <TextBox Text="{Binding x, Mode=TwoWay}">
			<TextBox.RenderTransform>
			    <TranslateTransform X="{Binding x, Mode=TwoWay}" Y="{Binding y, Mode=TwoWay}"/>
			</TextBox.RenderTransform>
		    </TextBox>
		</StackPanel>
	    </Border>
	</DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

MultiBinding silverlight 4 (баг №2)

Posted in C#, Ошибки, Silverlight 4, XAML with tags , , , , , , , on 03.06.2011 by prostocod

Продолжая серию статей Silverlight 4 step by step

Описание проблемы:

Решение проблемы с мультибайдингом я честно нашел в интернете, но справился с ней не сразу. В данной статье я расскажу что вам понадобиться и приведу пример конвертора Concat.


Решение проблемы отсутствия multibinding:

Первое, что вам нужно, это посетить блог scottlogic silverlight multibinding solution for silverlight-4/ — там подробно описано, что и как работает. Я же вам расскажу что конкретно вам нужно.
Второе, если вам не интересно читать английский блог, то просто скачайте SLMultiBindingUpdate.zip — этот проект у меня не запустился, но всё равно нам нужно от туда только 3 файла.

  • BindingUtil.cs
  • IMultiValueConverter.cs
  • MultiBinding.cs

Кидаем их в своей проект. Теперь нам нужно только осуществить байдинг, я вам покажу два способа:
XAML:

                                    <TextBlock>
                                        <SLMultiBinding:BindingUtil.MultiBinding>
                                            <SLMultiBinding:MultiBinding TargetProperty="Text" 
                                                                         Converter="{StaticResource   ConverterConcat}">
                                                <Binding Path="x"/>    
                                                <Binding Path="y"/>             
                                            </SLMultiBinding:MultiBinding>
                                        </SLMultiBinding:BindingUtil.MultiBinding>
                                    </TextBlock>

C# codebehind:

            var textBlock = new TextBlock();

            var binding = new MultiBinding()
                              {
                                  TargetProperty = "Text",
                                  Converter = new Helpers.Converter.ConcatConverter(),
                                  Bindings = new ObservableCollection<Binding>()
                                                 {
                                                     new Binding("x"),
                                                     new Binding("y")
                                                 },
                                  ConverterParameter = "{0}/{1}"

                              };

            SLMultiBinding.BindingUtil.SetMultiBinding(textBlock, binding);

            stack.Children.Add(textBlock);

Подождите не компилируйте, вам ещё нужен мой конвертор ConcatConverter, который просто делает конкатенацию строк.

ConcatConverter:

    public class ConcatConverter : IMultiValueConverter
    {

        public object Convert(object[] values, Type targetType,
          object parameter, System.Globalization.CultureInfo culture)
        {
            var strFormat = (String)parameter;
            if (strFormat == null)
            {
                var builder = new StringBuilder();
                foreach (var value in values)
                {
                    if (value != null)
                        builder.Append(value.ToString());
;
                }
                return builder.ToString();
            }
            else
            {
                for (int i = 0; i < values.Length; i++)
                {
                    var value = values[i];
                    if (value != null)
                        strFormat = strFormat.Replace("{" + i + "}", value.ToString());
                }
                return strFormat;
            }
            
        }

        public object[] ConvertBack(object value, Type[] targetTypes,
          object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

    }

Конвертор работает, с ConverterParameter(«{0}/{1}») и без ConverterParameter.

Вот и всё, теперь мы можем работать с мультибайдингом.

Binding TabControl в Silverlight-4 (баг №1)

Posted in C#, Silverlight 4, XAML with tags , , , , , , , , , on 02.06.2011 by prostocod

Это статья из серии Silverlight 4 баг за багом (шаг за шагом).

Описание проблемы :

Binding элемента TabControl, обычным способом не работает. т.е Описать элемент в DataTemplate не получится.

Решение: 

Нужно создать Converter, который будет возращать в ItemSource коллекцию из TabItems.

Converter :


public class SourceToTabItemsConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                var source = (IEnumerable)value;
                if (source != null)
                {
                    var controlTemplate = (ControlTemplate)parameter;

                    var tabItems = new List<TabItem>();

                    foreach (object item in source)
                    {
                        PropertyInfo[] propertyInfos = item.GetType().GetProperties();

                        //тут мы выбираем, то поле которое будет Header. Вы должны сами вводить это значение.
                        var propertyInfo = propertyInfos.First(x => x.Name == "name");

                        string headerText = null;
                        if (propertyInfo != null)
                        {
                            object propValue = propertyInfo.GetValue(item, null);
                            headerText = (propValue ?? string.Empty).ToString();
                        }

                        var tabItem = new TabItem
                                          {
                                              DataContext = item,
                                              Header = headerText,
                                              Content =
                                                  controlTemplate == null
                                                      ? item
                                                      : new ContentControl { Template = controlTemplate }
                                          };

                        tabItems.Add(tabItem);
                    }

                    return tabItems;
                }
                return null;
            }
            catch (Exception)
            {
                return null;
            }
        }

        /// <summary>
        /// ConvertBack method is not supported
        /// </summary>
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("ConvertBack method is not supported");
        }

Ещё нам понадобиться ControlTemplate, что бы использовать его в конвертере и создать нужный нам вид.

        <ControlTemplate x:Key="MyTabItemContentTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Path=name}" />
            </StackPanel>
        </ControlTemplate>

Вызов конвертера:

        <controls:TabControl  x:Name="tabControl"
        ItemsSource="{Binding ElementName=tabControl, 
                              Path=DataContext, 
                              Converter={StaticResource ConverterCollectionToTabItems}, 
                              ConverterParameter={StaticResource MyTabItemContentTemplate}}">
        </controls:TabControl>

Не забываем, что нужно декларировать сам конвертер.

...
           xmlns:converter="clr-namespace:Helpers.Converters">
    <navigation:Page.Resources>
        <converter:SourceToTabItemsConverter x:Key="ConverterCollectionToTabItems" />
...

Вот и всё. Надеюсь статья вам поможет.