I'm trying to create a UWP App which allows you to modify the colors of what the camera is showing on the fly. My current code is based on the Effective example by Nikola Metulev, and it modifies the camera view by using a IBasicVideoEffect. But I need to modify the colors while the camera is active (showing more red, for example).
I've searched for days, and I think my problem is that, as an IBasicVideoEffect must be in a separated class, I don't know how to pass a value (a Matrix5x4 in this case) from the MainPage to the Effect class.
Here is my code:
MainPage Class:
using ColorEffects;
using System;
using Windows.Media.Capture;
using Windows.Media.Effects;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace Color
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
private MediaCapture _mediaCapture;
public MainPage()
{
this.InitializeComponent();
}
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_mediaCapture = new MediaCapture();
var settings = new MediaCaptureInitializationSettings()
{
StreamingCaptureMode = StreamingCaptureMode.Video,
};
await _mediaCapture.InitializeAsync(settings);
captureElement.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
var effect = await _mediaCapture.AddVideoEffectAsync(
new VideoEffectDefinition(typeof(TheEffect).FullName),
MediaStreamType.VideoPreview);
}
}
}
ColorEffect Class:
using Microsoft.Graphics.Canvas;
using Microsoft.Graphics.Canvas.Brushes;
using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Graphics.Canvas.Text;
using System;
using System.Collections.Generic;
using System.Numerics;
using Windows.Foundation.Collections;
using Windows.Graphics.DirectX.Direct3D11;
using Windows.Media.Effects;
using Windows.Media.MediaProperties;
using Windows.UI.Text;
namespace ColorEffects
{
public sealed class TheEffect : IBasicVideoEffect
{
private IPropertySet _configuration;
private CanvasDevice _canvasDevice;
public void ProcessFrame(ProcessVideoFrameContext context)
{
using (var inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(_canvasDevice, context.InputFrame.Direct3DSurface))
using (var drawingSurface = CanvasRenderTarget.CreateFromDirect3D11Surface(_canvasDevice, context.OutputFrame.Direct3DSurface).CreateDrawingSession())
{
var matrix = new Matrix5x4() { M11 = 0.5f, M22 = 0.5f, M33 = 1.0f, M44 = 1.0f, M54 = 0.0f };
var colorEffect = new ColorMatrixEffect()
{
ColorMatrix = matrix,
Source = inputBitmap
};
drawingSurface.DrawImage(colorEffect);
}
}
public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
{
_canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device);
}
public bool IsReadOnly { get { return false; } }
public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
{
get
{
var properties = new List<VideoEncodingProperties>();
properties.Add(VideoEncodingProperties.CreateUncompressed("ARGB32", 640, 480));
return properties;
}
}
public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Gpu; } }
public bool TimeIndependent { get { return false; } }
public void DiscardQueuedFrames() { }
public void Close(MediaEffectClosedReason reason)
{
if (_canvasDevice != null)
_canvasDevice.Dispose();
}
public void SetProperties(IPropertySet configuration)
{
_configuration = configuration;
}
}
}
Can anyone help my out? Thank you very much!
With a little adjustment to your code, you can do the color change during video running, till you share the same object as a parameter in effect as well as a source object to change color
i.e.
public class TheEffectParameter
{
public Matrix5x4 ColorMatrix { get; set; }
}
public sealed class TheEffect: IBasicVideoEffect
{
private IPropertySet _configuration;
private CanvasDevice _canvasDevice;
public void ProcessFrame(ProcessVideoFrameContext context)
{
using (var inputBitmap = CanvasBitmap.CreateFromDirect3D11Surface(_canvasDevice, context.InputFrame.Direct3DSurface))
using (var drawingSurface = CanvasRenderTarget.CreateFromDirect3D11Surface(_canvasDevice, context.OutputFrame.Direct3DSurface).CreateDrawingSession())
{
Matrix5x4 matrix;
if (ColorParameter == null)
{
//Default if parameter not passed
matrix = new Matrix5x4() { M11 = 0.5f, M22 = 0.5f, M33 = 1.0f, M44 = 1.0f, M54 = 0.0f };
}
else
matrix = ColorParameter.ColorMatrix;
var colorEffect = new ColorMatrixEffect()
{
ColorMatrix = matrix,
Source = inputBitmap
};
drawingSurface.DrawImage(colorEffect);
}
}
public void SetEncodingProperties(VideoEncodingProperties encodingProperties, IDirect3DDevice device)
{
_canvasDevice = CanvasDevice.CreateFromDirect3D11Device(device);
}
public bool IsReadOnly { get { return false; } }
public IReadOnlyList<VideoEncodingProperties> SupportedEncodingProperties
{
get
{
var properties = new List<VideoEncodingProperties>();
properties.Add(VideoEncodingProperties.CreateUncompressed("ARGB32", 640, 480));
return properties;
}
}
public MediaMemoryTypes SupportedMemoryTypes { get { return MediaMemoryTypes.Gpu; } }
public bool TimeIndependent { get { return false; } }
public void DiscardQueuedFrames()
{
}
public void Close(MediaEffectClosedReason reason)
{
if (_canvasDevice != null)
_canvasDevice.Dispose();
}
public void SetProperties(IPropertySet configuration)
{
_configuration = configuration;
}
public TheEffectParameter ColorParameter
{
get
{
if (_configuration != null && _configuration.TryGetValue(nameof(ColorParameter), out object val))
return (TheEffectParameter)val;
return null;
}
}
}
and little Change on the main page :
TheEffectParameter parameter;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
_mediaCapture = new MediaCapture();
var settings = new MediaCaptureInitializationSettings()
{
StreamingCaptureMode = StreamingCaptureMode.Video,
};
await _mediaCapture.InitializeAsync(settings);
captureElement.Source = _mediaCapture;
await _mediaCapture.StartPreviewAsync();
parameter = new TheEffectParameter {
ColorMatrix = new Matrix5x4() { M11 = 0.5f, M22 = 0.5f, M33 = 1.0f, M44 = 1.0f, M54 = 0.0f }
};
var propertySet = new PropertySet();
propertySet.Add(nameof(TheEffect.ColorParameter), parameter);
var effect = await _mediaCapture.AddVideoEffectAsync(
new VideoEffectDefinition(typeof(TheEffect).FullName,propertySet),
MediaStreamType.VideoPreview);
}
public void ChangeColor(Matrix5x4 matrix)
{
if (parameter == null)
return;
parameter.ColorMatrix = matrix;
}
this might have a bug forgive me for that because I write this code using your's on the fly and haven't tested but it should work
Related
I have used ShellRenderer but I am unable to get the code working to add an extra space between the Tabbar line and the icons. Here is an image:
I need to increase the space between the gray line and Top of all icons.
Here is the code that I have tried.
[assembly: ExportRenderer(typeof(Shell), typeof(CustomShellRenderer))]
namespace MyProject.iOS.CustomRenderers
{
public class CustomShellRenderer : ShellRenderer
{
protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
{
var renderer = base.CreateShellSectionRenderer(shellSection);
if (renderer != null)
{
var a = (renderer as ShellSectionRenderer);
(renderer as ShellSectionRenderer).NavigationBar.Translucent = false;
}
return renderer;
}
protected override IShellItemRenderer CreateShellItemRenderer(ShellItem item)
{
var renderer = base.CreateShellItemRenderer(item);
(renderer as ShellItemRenderer).TabBar.Translucent = false;
(renderer as ShellItemRenderer).TabBar.ShadowImage = new UIImage();
(renderer as ShellItemRenderer).TabBar.BackgroundImage = new UIImage();
CGRect frame = (renderer as ShellItemRenderer).TabBar.Frame;
UIView view = new UIView();
view.BackgroundColor = UIColor.Yellow;
view.Frame = new CGRect(frame.X, frame.Y, frame.Width, 10);
(renderer as ShellItemRenderer).TabBar.AddSubview(view);
return renderer;
}
}
You can add a little ImageInsets of barItem to make a space between the gray line and Top of all icons. You can't add a extra view because the space is fixed.
public class MyShellRenderer : ShellRenderer
{
protected override IShellSectionRenderer CreateShellSectionRenderer(ShellSection shellSection)
{
var renderer = base.CreateShellSectionRenderer(shellSection);
if (renderer != null)
{
(renderer as ShellSectionRenderer).NavigationBar.SetBackgroundImage(UIImage.FromFile("monkey.png"), UIBarMetrics.Default);
}
return renderer;
}
protected override IShellTabBarAppearanceTracker CreateTabBarAppearanceTracker()
{
return new CustomTabbarAppearance();
}
}
public class CustomTabbarAppearance : IShellTabBarAppearanceTracker
{
public void Dispose()
{
}
public void ResetAppearance(UITabBarController controller)
{
}
public void UpdateLayout(UITabBarController controller)
{
UITabBar myTabBar = controller.TabBar;
foreach (var barItem in myTabBar.Items)
{
barItem.ImageInsets = new UIEdgeInsets(8, 0, 0, 0);
//barItem.TitlePositionAdjustment = new UIOffset(10, 0);
}
}
}
You can check my sample here.
I am creating a button with a gradient in Xamarin forms. I am successfully making it but when i later on in the code try to update its color, nothing happens in the UI.
This is how the project is setup:
XAML:
<controls:FullyColoredGradient x:Name = "SelectedBackground" StartColor = "Purple" EndColor="Yellow" />
If i then later on the code do a void and try to update these colors like this:
SelectedBackground.EndColor = Color.Red;
SelectedBackground.StartColor = Color.Blue;
Then nothing happens. They do not recolor.
This is how my shared code looks:
public class FullyColoredGradient : Button
{
public static readonly BindableProperty StartColorProperty =
BindableProperty.Create(nameof(StartColor),
typeof(Color), typeof(FullyColoredGradient),
Color.Default);
public Color StartColor
{
get { return (Color)GetValue(StartColorProperty); }
set { SetValue(StartColorProperty, value); }
}
public static readonly BindableProperty EndColorProperty =
BindableProperty.Create(nameof(EndColor),
typeof(Color), typeof(FullyColoredGradient),
Color.Default);
public Color EndColor
{
get { return (Color)GetValue(EndColorProperty); }
set { SetValue(EndColorProperty, value); }
}
}
And this is my iOS renderer:
public class TransparentGradientColor_iOS : ButtonRenderer
{
CGRect rect;
CAGradientLayer gradientLayer;
public TransparentGradientColor_iOS() { }
public override void Draw(CGRect rect)
{
base.Draw(rect);
this.rect = rect;
FullyColoredGradient rcv = (FullyColoredGradient)Element;
if (rcv == null)
return;
this.ClipsToBounds = true;
this.Layer.MasksToBounds = true;
FullyColoredGradient stack = (FullyColoredGradient)this.Element;
CGColor startColor = stack.StartColor.ToCGColor();
CGColor endColor = stack.EndColor.ToCGColor();
#region for Vertical Gradient
this.gradientLayer = new CAGradientLayer()
{
StartPoint = new CGPoint(0, 0.5),
EndPoint = new CGPoint(1, 0.5)
};
#endregion
gradientLayer.Frame = rect;
gradientLayer.Colors = new CGColor[] { startColor, endColor };
NativeView.Layer.InsertSublayer(gradientLayer, 0);
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
UpdateColor();
}
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
UpdateColor();
}
void UpdateColor()
{
if (gradientLayer != null)
{
FullyColoredGradient stack = (FullyColoredGradient)this.Element;
CGColor startColor = Xamarin.Forms.Color.White.ToCGColor();
CGColor endColor = Xamarin.Forms.Color.White.ToCGColor();
gradientLayer.Colors = new CGColor[] { startColor, endColor };
}
}
}
I have used this custom renderer, this will apply gradient to all buttons(you can create custom button if you want), you can try this out:
[assembly: ExportRenderer(typeof(Button), typeof(CustomButtonRendereriOS))]
namespace XYZ.iOS.Renderer
{
public class CustomButtonRendereriOS : ButtonRenderer
{
//To apply gradient background to button
public override CGRect Frame
{
get
{
return base.Frame;
}
set
{
if (value.Width > 0 && value.Height > 0)
{
foreach (var layer in Control?.Layer.Sublayers.Where(layer => layer is CAGradientLayer))
layer.Frame = new CGRect(0, 0, value.Width, value.Height);
}
base.Frame = value;
}
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
base.OnElementChanged(e);
if (e.OldElement == null)
{
try
{
var gradient = new CAGradientLayer();
gradient.CornerRadius = Control.Layer.CornerRadius = 5;
gradient.Colors = new CGColor[]
{
UIColor.FromRGB(243, 112, 33).CGColor,
UIColor.FromRGB(226, 64, 64).CGColor
};
var layer = Control?.Layer.Sublayers.LastOrDefault();
Control?.Layer.InsertSublayerBelow(gradient, layer);
}
catch (Exception ex)
{
}
}
}
}
You can also use a gradient stack layout/ Frame as described here with help of custom renderer and use Tap Gesture of it for clicked event.
Gradient Button in Xamarin Forms
Hope this may solve your issue.
I'm developing Pong with MvvmCross. The Paddles Y values change when holding the up and down buttons (buttons in the android view/activity - not keyboard buttons). However this is not being shown in the view (paddles stay in one spot, even though I can see in the console logs that the paddle has gone up or down).
Why are the paddles Y values not properly bound to the view?
Here is the code:
ViewModel:
using System.Linq;
using System.Text;
using System.Threading;
using Cirrious.MvvmCross.ViewModels;
using Pong.Core.ViewModels;
using Pong.Core.Models;
namespace Pong.Core.ViewModels
{
public class GamePlayViewModel
: MvxViewModel
{
private string _hello = "Hello MvvmCross";
public string Hello
{
get { return _hello; }
set { _hello = value; RaisePropertyChanged(() => Hello); }
}
private int _totalFramesBeenHad;
public int TotalFramesBeenHad
{
get { return _totalFramesBeenHad; }
set { _totalFramesBeenHad = value; RaisePropertyChanged(() => TotalFramesBeenHad); }
}
private PlayerPaddle _paddle1;
public int Paddle1
{
get { return _paddle1.Y; }
set { _paddle1.Y = value; RaisePropertyChanged(() => Paddle1); }
}
private ComputerPaddle _paddle2;
public int Paddle2
{
get { return _paddle2.Y; }
set { _paddle2.Y = value; RaisePropertyChanged(() => Paddle2); }
}
protected StandardBall StandardBall;
public GamePlayViewModel()
{
_paddle1 = new PlayerPaddle();
_paddle2 = new ComputerPaddle();
StandardBall = new StandardBall();
}
public void UpdatePaddle1()
{
switch (_paddle1.DetectWallCollision())
{
case "upper":
_paddle1.UpperWallHit();
break;
case "lower":
_paddle1.LowerWallHit();
break;
case "none":
_paddle1.MoveOneFrame();
break;
}
}
public void UpdateBall()
{
if (StandardBall.DetectWallCollision()) StandardBall.HandleWallCollision();
StandardBall.MoveOneFrame();
}
public void SetPaddleDirection(string direction)
{
_paddle1.SetDirection(direction);
}
public void StopPaddle()
{
_paddle1.StopMoving();
}
}
}
child viewmodel (actual one used):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Pong.Core.ViewModels;
using Pong.Core.Models;
using Pong.Droid.Views;
namespace Pong.Droid.ViewModels
{
public class GamePlayViewModelAndroid : GamePlayViewModel
{
public readonly Timer _dispatcherTimer;
public GamePlayView gpv;
public GamePlayViewModelAndroid (GamePlayView gpv)
{
this.gpv = gpv;
TimerCallback timerDelegate = new TimerCallback (Tick);
_dispatcherTimer = new Timer (timerDelegate, null, 0, 1000/Court.FPS);
}
public void Tick(object state)
{
UpdatePaddle1();
gpv.move ();
}
}
}
View:
using Android.App;
using Android.OS;
using Cirrious.MvvmCross.Droid.Views;
using Cirrious;
using Cirrious.CrossCore;
using Cirrious.MvvmCross.Binding;
using Cirrious.MvvmCross.ViewModels;
using Pong.Droid.ViewModels;
using Android.Content.PM;
using Pong.Droid;
using Android.Views;
using Android.Widget;
using Android.Graphics;
using Android.Content;
using Android.Content.Res;
using Cirrious.MvvmCross.Binding.BindingContext;
using Pong.Core.Models;
namespace Pong.Droid.Views
{
[Activity(Label = "!PONG!", ScreenOrientation = ScreenOrientation.Landscape)]
public class GamePlayView : MvxActivity
{
private GamePlayViewModelAndroid _viewModel;
private Button _buttonUp;
private Button _buttonDown;
public GameView GameView;
public LinearLayout ParentLayout;
public LinearLayout ButtonsLayout;
public int _paddle1y;
public int _paddle2y;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
GameView = new GameView (this);
_viewModel = new GamePlayViewModelAndroid(this);
SetUpControls ();
SetUpButtonEvents ();
SetContentView(ParentLayout);
DataContext = _viewModel;
this.ClearAllBindings();
var set = this.CreateBindingSet<GamePlayView, GamePlayViewModelAndroid>();
set.Bind(this).For(v => v._paddle1y).To(vm => vm.Paddle1);
set.Bind(this).For(v => v._paddle2y).To(vm => vm.Paddle2);
set.Apply();
}
void SetUpButtonEvents ()
{
_buttonUp.Touch += (s, e) => {
var handled = false;
if (e.Event.Action == MotionEventActions.Down) {
_viewModel.SetPaddleDirection ("up");
handled = true;
}
else
if (e.Event.Action == MotionEventActions.Up) {
_viewModel.StopPaddle ();
handled = true;
}
e.Handled = handled;
};
_buttonDown.Touch += (s, e) => {
var handled = false;
if (e.Event.Action == MotionEventActions.Down) {
_viewModel.SetPaddleDirection ("down");
handled = true;
}
else
if (e.Event.Action == MotionEventActions.Up) {
_viewModel.StopPaddle ();
handled = true;
}
e.Handled = handled;
};
}
void SetUpControls ()
{
_buttonUp = new Button (this);
_buttonDown = new Button (this);
ParentLayout = new LinearLayout (this);
ButtonsLayout = new LinearLayout (this);
ParentLayout.Orientation = Android.Widget.Orientation.Horizontal;
ButtonsLayout.Orientation = Android.Widget.Orientation.Vertical;
ButtonsLayout.AddView (_buttonUp);
ButtonsLayout.AddView (_buttonDown);
ParentLayout.AddView (ButtonsLayout);
ParentLayout.AddView (GameView);
}
public void move() {
//GameView.paddle1y = _viewModel.Paddle1.Y;
//GameView.paddle2y = _viewModel.Paddle2.Y;
RunOnUiThread (() => GameView.Invalidate ());
}
}
public class GameView : View {
private Bitmap _paddleBmp;
private int _paddle1x;
public int _paddle1y;
private int _paddle2x;
public int _paddle2y;
public GamePlayViewModelAndroid vm;
public GamePlayView View;
public GameView(Context context) : base (context) {
SetPaddleBmp ();
// this.ClearAllBindings();
// var set = this.CreateBindingSet<GameView, GamePlayViewModelAndroid>();
// set.Bind(_paddle1y).To(vm => vm.Paddle1.Y);
// set.Bind(_paddle2y).To(vm => vm.Paddle2.Y);
// set.Apply();
//var set = this.CreateBindingSet<PolicySummaryCell, PolicyComponent<BasePolicy>>();
//set.Bind(_periodOfInsurance).To(vm => vm.PeriodOfInsurance);
//set.Bind(_title).To(vm => vm.Title);
View = (GamePlayView)context;
}
void SetPaddleBmp ()
{
var paddlebmpTemp = BitmapFactory.DecodeResource (Resources, Resource.Drawable.Icon);
_paddleBmp = Bitmap.CreateScaledBitmap (paddlebmpTemp, Paddle.Width, Paddle.Height, false);
}
protected override void OnDraw(Canvas canvas) {
canvas.DrawColor(Color.Aqua);
canvas.DrawBitmap (_paddleBmp, _paddle1x, View._paddle1y, null);
canvas.DrawBitmap (_paddleBmp, _paddle2x, View._paddle2y, null);
}
protected override void OnSizeChanged(int w, int h, int oldw, int oldh) {
SetUpCourt (w, h);
}
void SetUpCourt (int w, int h)
{
Court.Width = w;
Court.Height = h;
Court.UpperBound = 0;
Court.LowerBound = h;
Court.LeftBound = 0;
Court.RightBound = w;
ComputerPaddle.X = Court.RightBound - Paddle.Width - 20;
_paddle2x = ComputerPaddle.X;
_paddle1x = PlayerPaddle.X;
}
}
}
Model:
using System.Diagnostics;
namespace Pong.Core.Models
{
public class Paddle
{
public int Y { get; set; }
public int VY { get; set; }
public static readonly int Speed = 600;
public static readonly int Height = 300;
public static readonly int Width = 100;
public void StopMoving()
{
VY = 0;
}
public void SetDirection(string direction)
{
if (direction == "up")
{
VY = -Speed;
}
else if (direction == "down")
{
VY = Speed;
}
}
public string DetectWallCollision()
{
if (Y < Court.UpperBound)
{
return "upper";
}
if (Y > (Court.LowerBound - Paddle.Height))
{
return "lower";
}
return "none";
}
public void UpperWallHit()
{
StopMoving();
Y = Court.UpperBound;
Debug.WriteLine("You hit the top wall");
}
public void LowerWallHit()
{
StopMoving();
Y = Court.LowerBound - Paddle.Height;
Debug.WriteLine("You hit the bottom wall");
}
public void MoveOneFrame()
{
Y += VY/Court.FPS;//this should trigger the RaisePropertyChanged(() => Paddle1)
}
}
public class PlayerPaddle : Paddle {
public static readonly int X = 20;
}
public class ComputerPaddle : Paddle {
public static int X;
}
}
I think your problem here, is that you're updating the Paddle.Y field, but the RaisePropertyChanged() called as your update the Paddle (on set).
See the difference?
Only if you'll set new instance of Paddle1 and Paddle2 property in GamePlayViewModel the setter will be called:
Paddle1 = new Paddle(); //will call the setter of Paddle1 property
Paddle1.Y = 90; //would not call the setter property
What you need to do is to call RaisePropertyChanged when you update the X and Y values of Paddle1 and Paddle2 properties.
The answer to this question is that on the view, to bind a field to the viewModel programmatically, the field must be a property with a getter and setter. Just like this. In the view:
public int _paddle1y { get; set; }
public int _paddle2y { get; set; }
I don't know why this is the case. I think it's a bit of a bug in MvvmCross. But maybe there is a valid reason for it.
Instead of calling _paddle1 directly, call Paddle1 (and 2) so the RaisePropertyChanged event will get called.
Why cannot change MonoTouch.Dialog.TableView.Background color ? I am using the Elements API of MonoTouch.Dialog. It's still gray!
class MyDialogViewController : DialogViewController {
public MyDialogViewController (RootElement root) : base (root)
{
}
public override void LoadView ()
{
base.LoadView ();
TableView.BackgroundColor = UIColor.Clear;
UIImage background = UIImage.FromFile ("Mybackground.png");
ParentViewController.View.BackgroundColor = UIColor.FromPatternImage (background);
}
}
public partial class MyVC: UINavigationController
{
public void CreateTestUI()
{
var menu = new RootElement("MyMenu"){
new Section ("test"){
new StringElement("Test", delegate() { }), ...
var dv = new MyDialogViewController (menu) {
Autorotate = true
};
// add the nav controller to the window
this.PushViewController (dv, true);
}
}
in iPad,must add this line: TableView.BackgroundView = null;
Now it works well,thanks poupou, thanks to all.
public override void LoadView()
{
base.LoadView();
TableView.BackgroundView = null;
TableView.BackgroundColor = UIColor.Black;
}
Is there a way to programatically create a RichTextBoxAppender using log4net?
In other words no xml app.config?
using System;
using System.Windows.Forms;
using System.Drawing;
using log4net;
using log4net.Core;
using log4net.Appender;
using log4net.Util;
namespace Vip.Logging
{
/// <summary>
/// Description of RichTextBoxAppender.
/// </summary>
public class RichTextBoxAppender : AppenderSkeleton
{
#region Private Instance Fields
private RichTextBox richTextBox = null;
private Form containerForm = null;
private LevelMapping levelMapping = new LevelMapping();
private int maxTextLength = 100000;
#endregion
private delegate void UpdateControlDelegate(LoggingEvent loggingEvent);
#region Constructor
public RichTextBoxAppender(RichTextBox myRichTextBox) : base()
{
richTextBox = myRichTextBox;
containerForm = (Form)richTextBox.Parent;
}
#endregion
private void UpdateControl(LoggingEvent loggingEvent)
{
// There may be performance issues if the buffer gets too long
// So periodically clear the buffer
if (richTextBox.TextLength > maxTextLength)
{
richTextBox.Clear();
richTextBox.AppendText(string.Format("(Cleared log length max: {0})\n", maxTextLength));
}
// look for a style mapping
LevelTextStyle selectedStyle = levelMapping.Lookup(loggingEvent.Level) as LevelTextStyle;
if (selectedStyle != null)
{
// set the colors of the text about to be appended
richTextBox.SelectionBackColor = selectedStyle.BackColor;
richTextBox.SelectionColor = selectedStyle.TextColor;
// alter selection font as much as necessary
// missing settings are replaced by the font settings on the control
if (selectedStyle.Font != null)
{
// set Font Family, size and styles
richTextBox.SelectionFont = selectedStyle.Font;
}
else if (selectedStyle.PointSize > 0 && richTextBox.Font.SizeInPoints != selectedStyle.PointSize)
{
// use control's font family, set size and styles
float size = selectedStyle.PointSize > 0.0f ? selectedStyle.PointSize : richTextBox.Font.SizeInPoints;
richTextBox.SelectionFont = new Font(richTextBox.Font.FontFamily.Name, size, selectedStyle.FontStyle);
}
else if (richTextBox.Font.Style != selectedStyle.FontStyle)
{
// use control's font family and size, set styles
richTextBox.SelectionFont = new Font(richTextBox.Font, selectedStyle.FontStyle);
}
}
richTextBox.AppendText(RenderLoggingEvent(loggingEvent));
}
protected override void Append(LoggingEvent LoggingEvent)
{
if (richTextBox.InvokeRequired)
{
richTextBox.Invoke(
new UpdateControlDelegate(UpdateControl),
new object[] { LoggingEvent });
}
else
{
UpdateControl(LoggingEvent);
}
}
public void AddMapping(LevelTextStyle mapping)
{
levelMapping.Add(mapping);
}
public override void ActivateOptions()
{
base.ActivateOptions();
levelMapping.ActivateOptions();
}
protected override bool RequiresLayout { get { return true; } }
}
public class LevelTextStyle : LevelMappingEntry
{
private Color textColor;
private Color backColor;
private FontStyle fontStyle = FontStyle.Regular;
private float pointSize = 0.0f;
private bool bold = false;
private bool italic = false;
private string fontFamilyName = null;
private Font font = null;
public bool Bold { get { return bold; } set { bold = value; } }
public bool Italic { get { return italic; } set { italic = value; } }
public float PointSize { get { return pointSize; } set { pointSize = value; } }
/// <summary>
/// Initialize the options for the object
/// </summary>
/// <remarks>Parse the properties</remarks>
public override void ActivateOptions()
{
base.ActivateOptions();
if (bold) fontStyle |= FontStyle.Bold;
if (italic) fontStyle |= FontStyle.Italic;
if (fontFamilyName != null)
{
float size = pointSize > 0.0f ? pointSize : 8.25f;
try
{
font = new Font(fontFamilyName, size, fontStyle);
}
catch (Exception)
{
font = new Font("Arial", 8.25f, FontStyle.Regular);
}
}
}
public Color TextColor { get { return textColor; } set { textColor = value; } }
public Color BackColor { get { return backColor; } set { backColor = value; } }
public FontStyle FontStyle { get { return fontStyle; } set { fontStyle = value; } }
public Font Font { get { return font; } set { font = value; } }
}
}
public partial class MainForm : Form
{
private static string locPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
private static string dskPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
private RichTextBoxAppender rba;
private MessageBoxAppender mba;
public MainForm()
{
InitializeComponent();
if (!Global.logger.Logger.Repository.Configured)
{
rba = new RichTextBoxAppender(richTextBoxLog);
rba.Threshold = Level.All;
rba.Layout = new PatternLayout("%date{dd-MM-yyyy HH:mm:ss.fff} %5level %message %n");
LevelTextStyle ilts = new LevelTextStyle();
ilts.Level = Level.Info;
ilts.TextColor = Color.Yellow;
ilts.PointSize = 10.0f;
rba.AddMapping(ilts);
LevelTextStyle dlts = new LevelTextStyle();
dlts.Level = Level.Debug;
dlts.TextColor = Color.LightBlue;
dlts.PointSize = 10.0f;
rba.AddMapping(dlts);
LevelTextStyle wlts = new LevelTextStyle();
wlts.Level = Level.Warn;
wlts.TextColor = Color.Chartreuse;
wlts.PointSize = 10.0f;
rba.AddMapping(wlts);
LevelTextStyle elts = new LevelTextStyle();
elts.Level = Level.Error;
elts.TextColor = Color.Crimson;
elts.BackColor = Color.Cornsilk;
elts.PointSize = 10.0f;
rba.AddMapping(elts);
BasicConfigurator.Configure(rba);
rba.ActivateOptions();
mba = new MessageBoxAppender();
mba.Layout = new PatternLayout("%date{dd-MM-yyyy HH:mm:ss.fff} %5level %message %n");
mba.Threshold = Level.Error;
BasicConfigurator.Configure(mba);
mba.ActivateOptions();
RollingFileAppender fa = new RollingFileAppender();
fa.AppendToFile = true;
fa.Threshold = log4net.Core.Level.All;
fa.RollingStyle = RollingFileAppender.RollingMode.Size;
fa.MaxFileSize = 100000;
fa.MaxSizeRollBackups = 3;
fa.File = dskPath + #"\FgPleoraLog.txt";
fa.Layout = new log4net.Layout.PatternLayout("%date{dd-MM-yyyy HH:mm:ss.fff} %5level %message (%logger{1}:%line)%n");
log4net.Config.BasicConfigurator.Configure(fa);
fa.ActivateOptions();
}
}
#GMAN 's answer is correct, but Invoke => BeginInvoke can be thread-safe. you can look my thread Why my log4net is deadlocked?